Skip to content
This repository has been archived by the owner on Oct 23, 2024. It is now read-only.

Commit

Permalink
fix(resolvers): allow undefined as return value
Browse files Browse the repository at this point in the history
Closes #17
  • Loading branch information
alexstrat authored and DanielMSchmidt committed Mar 26, 2019
1 parent af83c91 commit 68334fd
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 3 deletions.
23 changes: 21 additions & 2 deletions src/__tests__/graphqlObservable-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ const fieldResolverSchema = makeExecutableSchema({
type Plain {
noFieldResolver: String!
fieldResolver: String!
fieldResolvesUndefined: String!
giveMeTheParentFieldResolver: String!
giveMeTheArgsFieldResolver(arg: String!): String!
giveMeTheContextFieldResolver: String!
Expand Down Expand Up @@ -126,6 +127,9 @@ const fieldResolverSchema = makeExecutableSchema({
fieldResolver() {
return of("I am a field resolver");
},
fieldResolvesUndefined() {
return of(undefined);
},
giveMeTheParentFieldResolver(parent) {
return of(JSON.stringify(parent));
},
Expand Down Expand Up @@ -250,7 +254,7 @@ describe("graphqlObservable", function() {
}
`;

const expectedData = [{ name: "apollo11" }, { name: "challenger" }];
const expectedData = [{ name: "apollo11", firstFlight: null }, { name: "challenger", firstFlight: null }];
const dataSource = of(expectedData);
const expected = m.cold("(a|)", {
a: { data: { launched: [expectedData[0]] } }
Expand Down Expand Up @@ -282,7 +286,7 @@ describe("graphqlObservable", function() {
}
`;

const expectedData = [{ name: "apollo13" }, { name: "challenger" }];
const expectedData = [{ name: "apollo13", firstFlight: null }, { name: "challenger", firstFlight: null }];
const dataSource = of(expectedData);
const expected = m.cold("(a|)", {
a: { data: { launched: [expectedData[0]] } }
Expand Down Expand Up @@ -400,6 +404,21 @@ describe("graphqlObservable", function() {
m.expect(result.pipe(take(1))).toBeObservable(expected);
});

itMarbles("if defined but returns undefined, field is null", function (m) {
const query = gql`
query {
plain {
fieldResolvesUndefined
}
}
`;
const expected = m.cold("(a|)", {
a: { data: { plain: { fieldResolvesUndefined: null } } }
});
const result = graphql(fieldResolverSchema, query, null, {});
m.expect(result.pipe(take(1))).toBeObservable(expected);
});

itMarbles("the field resolvers 1st argument is parent", function(m) {
const query = gql`
query {
Expand Down
8 changes: 8 additions & 0 deletions src/jstutils/isNullish.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// inspired from https://github.com/graphql/graphql-js/blob/926e4d80c558b107c49e9403e943086fa9b043a8/src/jsutils/isNullish.js

/**
* Returns true if a value is null, undefined, or NaN.
*/
export default function isNullish(value: any) {
return value === null || value === undefined || value !== value;
};
6 changes: 5 additions & 1 deletion src/reactive-graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import {
parse,
} from "graphql";

import isNullish from './jstutils/isNullish';

// WARNING: This is NOT a spec complete graphql implementation
// https://facebook.github.io/graphql/October2016/

Expand Down Expand Up @@ -136,7 +138,9 @@ export default function graphql<T = object>(
context,
variables,
parent
);
)
// If result value is null-ish (null, undefined, or NaN) then return null.
.pipe(map(value => isNullish(value) ? null : value));

// Directly return the leaf nodes
if (definition.selectionSet === undefined) {
Expand Down

0 comments on commit 68334fd

Please sign in to comment.