-
Notifications
You must be signed in to change notification settings - Fork 61
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
Update GraphQL models after form submission #14
Comments
Where this is currently at: We're not going to be doing form submissions through GraphQL mutations at this stage due to larger form refactor (silverstripe/silverstripe-framework#6362). The code for doing such mutations has been developed to a certain extent (#17) and could be used in the future if needed... The decided approach for updating record data outside of using mutations is to have the Part 1 - FormSchema providing a list of changed recordsThe server needs to let Apollo know what typenames are new, deleted and updated.
Initially this FormSchema API will be manual, developers will need to manually flag changed and created records, however this API would be the starting block and could be automated through interface GraphQLDocument {
public function getDataIdFromObject();
}
class DataObjectGraphQLExtension extends DataExtension implements GraphQLDocument {
public function getDataIdFromObject() {
return sprintf("%s:%s", $this->owner->ClassName, $this->owner->ID);
}
}
$form->markRecordCreated(GraphQLDocument $record);
$form->markRecordDeleted(GraphQLDocument $record);
$form->markRecordChanged(GraphQLDocument $record); Part 2 - GraphQL taking that information and updating it.Given a list of changes off the server we need to update the React store outside of a mutation / Tasks
|
I've read through apollographql/apollo-client#951, lots of interesting discussion happening there! The Apollo maintainers want to make the internal cache structure part of the API, which is encouraging for our use case (e.g. "find all queries related to data object id"). Many of the advanced caching strategies would be a "nice to have" for us, I'd expect most of our logic to simply call The important issue for us is decoupling: Both individual queries and third party modules should be able to influence state and query invalidation based on our result objects returned from mutations. Here's a sketch what this could look like for a straight-up invalidation. I've changed the response signature to const saveFormMutation = gql`mutation saveForm($formId:!String, $data:FormData) {
recordUpdatesById {
type
id
updateType <-- created | updated | deleted
}
}`;
const getPageTreeQuery = gql`query getPageTree() {
treeNodes {
id
title
}
}`;
function invalidateQuery(state, queryName) {
const newState = state;
// loop through state and delete all related entries
// e.g. "$ROOT_QUERY.readFiles({id:0}).
// Would require a higher level abstraction in Apollo
return newState;
}
const cacheReducers = {
// Could be registered by third party code, through a registry system
pageTreeReducer: (args, prev, action) => {
if (action.type === 'APOLLO_MUTATION_RESULT' && action.result.recordUpdatesById) {
const hasApplicableRecords = action.result.recordUpdatesById.filter(update => type === 'Page').length;
if (hasApplicableRecords) {
// Invalidate queries by removing their data based on their name
return invalidateQuery(prev, 'getPageTree')
} else {
return prev;
}
} else {
return prev;
}
}
};
const client = new ApolloClient({
cacheReducers,
}); Some potential use cases from the current UI implementation:
Overall, I think we can go a long way with strategically placed |
Moving this out of the milestone since it's blocked by pending work in the upstream library. Craeted a spike card to reflect the effort involved so far: #33 |
…e-object API Remove object class references
Overview
Since forms don't always have a 1:1 mapping to DataObjects, there's a need for a "form state" abstraction. While forms can be submitted through GraphQL (see #10 and #17), they're not returning direct GraphQL types in a form submission response. This means we can't rely on GraphQL's built-in cache updating logic.
If we separate form submissions from DataObject GraphQL types, we need way for the submission handling to indicate to the client which data has gone stale (either delivering new data in the response, or triggering a fetch from the client). The PoC simply does a refetch() of the GraphQL query bound to
<AssetAdmin>
, which only works because it happens to query data which is changed through the form (in order to list files and folders). That's not a strong correlation though, e.g. aModelAdmin
form builder component won't necessarily query the DataObject GraphQL type which is submitted through the form. The Apollo client does not have an API to identify which queries track a particular object as identified by its client-side Apollo identifier (see dataObjectFromId), so we don't know which queries would need to be retriggered. This also rules out the updateQueries and refetchQueries option inmutate()
.Form submissions can't easily return arbitrary GraphQL representations of changed objects because there's no API to specifically update Apollo's stored objects outside of it's own query/mutation response processing. See updateQueries by id (dataIdFromObject) discussion. There's some ideas around a cache reducer to invalidate or update individual objects.
Note that this needs to be resolved even if we don't submit forms through GraphQL - the submission will still alter/invalidate existing GraphQL caches. For example, if we retrieve the page tree via GraphQL, publishing a page will alter the "published" status of its page tree node.
Related
Related:
The text was updated successfully, but these errors were encountered: