Open zopf opened 8 years ago
Here's my hack to make deletions possible: https://github.com/wellth-app/graffiti-mongoose/commit/886e8f3bbae16bf7d08db568203f74ea49a3433c
... and then I made this middleware that I can drop into my Koa stack to grab null variables from things that look like mutations and add their paths to the deletions
argument:
function getPathsToNull(tree, parentPath) {
const nullPaths = [];
for (const key in tree) {
if (tree[key] === null) {
// add to null paths
nullPaths.push(
parentPath ?
[parentPath, key].join('.') :
key
);
} else if (tree[key] instanceof Object) {
// descend
nullPaths.push.apply(nullPaths, getPathsToNull(
tree[key],
parentPath ?
[parentPath, key].join('.') :
key
));
}
}
return nullPaths;
}
function * handleNullVariables(next) {
const body = this.request.body;
const { query, variables } = Object.assign({}, body, this.query);
// TODO: properly parse the full query AST to determine if actually an add/update mutation
if (query && /mutation[\s\S]*{\s*(update|add)[a-zA-Z_]+\s*\(/i.test(query)) {
const parsedVariables = (typeof variables === 'string' && variables.length > 0) ?
JSON.parse(variables) : variables;
for (const key in parsedVariables) {
if ({}.hasOwnProperty.call(parsedVariables, key)) {
const deletions = getPathsToNull(parsedVariables[key]);
if (deletions && parsedVariables[key] !== null) {
parsedVariables[key].deletions = deletions;
}
}
}
const correctedVariables = JSON.stringify(parsedVariables);
// set both GET and POST vars
this.request.body.variables = correctedVariables;
this.query.variables = correctedVariables;
}
yield next;
}
export default handleNullVariables;
Overview of the Issue
I cannot easily update a field on an object that currently has a value to be
null
.It seems this is because the
graphql-js
library is stripping null variables that get passed to it, since the GraphQL spec currently does not have a concept of a null field value. Please see https://github.com/graphql/graphql-js/issues/133 and https://github.com/facebook/graphql/pull/83 for further information and hand-wringing.Reproduce the Error
For example, if I have a model named
User
, andUser
has a fieldfirstName
, if I run anaddUser
mutation withfirstName
set to "Alex", but then want to setfirstName
on that same object to benull
, I cannot.I can try to send the following update mutation:
with variables:
... but when I do, I will still receive:
Suggest a Fix
As suggested in https://github.com/graphql/graphql-js/issues/133#issuecomment-132751201, it seems like adding a
deletions
field is a viable possibility to work around the fact that the GraphQL folks seem very hesitant to implement a nativenull
value. I'm working on that myself right now in the https://github.com/wellth-app/graffiti-mongoose fork (which has by now diverged quite a bit).I'm also tossing around the idea of creating my own pre-
graffiti
middleware that notes allnull
values in thevariables
tree and adds their path to a top-leveldeletions
array on thevariables
tree, so that our existing clients don't have to implement the newdeletions
field.