Skip to content

Commit

Permalink
Merge pull request #251 from eduardolundgren/v8.0.0-relay-v15-require…
Browse files Browse the repository at this point in the history
…d-support-issue

Highlight Issue: Todo example with Relay v15.0.0 and fix @required field
  • Loading branch information
morrys authored Sep 7, 2023
2 parents 3894bb0 + 0e64f9f commit 33ee473
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 35 deletions.
82 changes: 62 additions & 20 deletions examples/relay-hook-example/todo/data/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -39,38 +39,58 @@ type Mutation {
addTodo(input: AddTodoInput!): AddTodoPayload
changeTodoStatus(input: ChangeTodoStatusInput!): ChangeTodoStatusPayload
markAllTodos(input: MarkAllTodosInput!): MarkAllTodosPayload
removeCompletedTodos(input: RemoveCompletedTodosInput!): RemoveCompletedTodosPayload
removeCompletedTodos(
input: RemoveCompletedTodosInput!
): RemoveCompletedTodosPayload
removeTodo(input: RemoveTodoInput!): RemoveTodoPayload
renameTodo(input: RenameTodoInput!): RenameTodoPayload
}

"""An object with an ID"""
"""
An object with an ID
"""
interface Node {
"""The id of the object."""
"""
The id of the object.
"""
id: ID!
}

"""Information about pagination in a connection."""
"""
Information about pagination in a connection.
"""
type PageInfo {
"""When paginating forwards, are there more items?"""
"""
When paginating forwards, are there more items?
"""
hasNextPage: Boolean!

"""When paginating backwards, are there more items?"""
"""
When paginating backwards, are there more items?
"""
hasPreviousPage: Boolean!

"""When paginating backwards, the cursor to continue."""
"""
When paginating backwards, the cursor to continue.
"""
startCursor: String

"""When paginating forwards, the cursor to continue."""
"""
When paginating forwards, the cursor to continue.
"""
endCursor: String
}

type Query {
user(id: String): User

"""Fetches an object given its ID"""
"""
Fetches an object given its ID
"""
node(
"""The ID of an object"""
"""
The ID of an object
"""
id: ID!
): Node
}
Expand Down Expand Up @@ -110,35 +130,57 @@ type RenameTodoPayload {
}

type Todo implements Node {
"""The ID of an object"""
"""
The ID of an object
"""
id: ID!
text: String!
text: String
complete: Boolean!
}

"""A connection to a list of items."""
"""
A connection to a list of items.
"""
type TodoConnection {
"""Information to aid in pagination."""
"""
Information to aid in pagination.
"""
pageInfo: PageInfo!

"""A list of edges."""
"""
A list of edges.
"""
edges: [TodoEdge]
}

"""An edge in a connection."""
"""
An edge in a connection.
"""
type TodoEdge {
"""The item at the end of the edge"""
"""
The item at the end of the edge
"""
node: Todo

"""A cursor for use in pagination"""
"""
A cursor for use in pagination
"""
cursor: String!
}

type User implements Node {
"""The ID of an object"""
"""
The ID of an object
"""
id: ID!
userId: String!
todos(status: String = "any", after: String, first: Int, before: String, last: Int): TodoConnection
todos(
status: String = "any"
after: String
first: Int
before: String
last: Int
): TodoConnection
totalCount: Int!
completedCount: Int!
}
4 changes: 2 additions & 2 deletions examples/relay-hook-example/todo/data/schema/nodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ const GraphQLTodo = new GraphQLObjectType({
fields: {
id: globalIdField('Todo'),
text: {
type: new GraphQLNonNull(GraphQLString),
resolve: (todo: Todo): string => todo.text,
type: GraphQLString,
resolve: (todo: Todo): string => null,
},
complete: {
type: new GraphQLNonNull(GraphQLBoolean),
Expand Down
9 changes: 8 additions & 1 deletion examples/relay-hook-example/todo/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,17 @@ function fetchQuery(
sink.next(data);
sink.complete();
});
})
});
}

const requiredFieldLogger = (fieldPath, fieldName) => {
console.error(
`Required field "${fieldName}" is null at path "${fieldPath}".`,
);
};

const modernEnvironment: Environment = new Environment({
requiredFieldLogger,
network: Network.create(fetchQuery),
store: new Store(new RecordSource()),
});
Expand Down
6 changes: 3 additions & 3 deletions examples/relay-hook-example/todo/js/components/Todo.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const fragmentSpecTodo = graphql`
fragment Todo_todo on Todo {
complete
id
text
text @required(action: THROW)
}
`;
const fragmentSpecUser = graphql`
Expand All @@ -54,8 +54,8 @@ const fragmentSpecUser = graphql`
const Todo = props => {
const user = useFragment(fragmentSpecUser, props.user);
console.log('props.todo', props.todo);
//const todo = useFragment(fragmentSpecTodo, props.todo);
const {todo} = props;
const todo = useFragment(fragmentSpecTodo, props.todo);
//const {todo} = props;
const [isEditing, setIsEditing] = useState<boolean>(false);

const [mutateChange] = useMutation(mutationChange);
Expand Down
4 changes: 1 addition & 3 deletions examples/relay-hook-example/todo/js/components/TodoList.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,7 @@ const fragmentSpec = graphql`
const fragmentSpecList = graphql`
fragment TodoList_edges on TodoEdge @relay(plural: true) {
node {
complete
id
text
...Todo_todo
}
}
`;
Expand Down
12 changes: 9 additions & 3 deletions examples/relay-hook-example/todo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"private": true,
"scripts": {
"start": "babel-node ./server.js",
"build": "relay-compiler --src ./js/ --schema ./data/schema.graphql --artifactDirectory ./__generated__/relay",
"build": "relay-compiler",
"flow-typed": "flow-typed install --flowVersion=0.94.0",
"update-schema": "babel-node ./scripts/updateSchema.js",
"lint": "eslint ./ --cache"
Expand All @@ -16,7 +16,7 @@
"prop-types": "^15.7.2",
"react": "^16.12.0",
"react-dom": "^16.8.4",
"relay-runtime": "12.0.0",
"relay-runtime": "15.0.0",
"relay-hooks": "6.0.0",
"whatwg-fetch": "3.0.0",
"isomorphic-fetch": "2.2.1",
Expand Down Expand Up @@ -47,7 +47,7 @@
"flow-bin": "^0.94.0",
"flow-typed": "^2.5.1",
"prettier": "^1.16.4",
"relay-compiler": "12.0.0",
"relay-compiler": "15.0.0",
"webpack": "^5.56.1",
"webpack-dev-server": "^3.2.1"
},
Expand All @@ -56,5 +56,11 @@
"trailingComma": "all",
"bracketSpacing": false,
"jsxBracketSameLine": true
},
"relay": {
"src": "./js/",
"schema": "./data/schema.graphql",
"artifactDirectory": "./__generated__/relay",
"language": "javascript"
}
}
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
},
"peerDependencies": {
"react": "^16.9.0 || ^17 || ^18",
"relay-runtime": "^13.0.2 || ^14.0.0 || ^15.0.0"
"relay-runtime": "^13.2.0 || ^14.0.0 || ^15.0.0"
},
"devDependencies": {
"babel-preset-fbjs": "^3.3.0",
Expand Down
23 changes: 23 additions & 0 deletions src/FragmentResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
getPaginationVariables,
getRefetchMetadata,
getValueAtPath,
handlePotentialSnapshotErrors,
} from 'relay-runtime';
import { Fetcher, fetchResolver } from './FetchResolver';
import { getConnectionState, getStateFromConnection } from './getConnectionState';
Expand Down Expand Up @@ -338,6 +339,10 @@ export class FragmentResolver {
// useFragment
this.result = data;
}
const snap = this.resolverData.snapshot;
if (snap) {
this._throwOrLogErrorsInSnapshot(snap);
}
this._subscribeResolve && this._subscribeResolve(this.result);
}

Expand Down Expand Up @@ -621,4 +626,22 @@ export class FragmentResolver {
this.refreshHooks();
return disposable;
};

_throwOrLogErrorsInSnapshot(snapshot: any) {
if (Array.isArray(snapshot)) {
snapshot.forEach((s) => {
if (s.missingRequiredFields) {
handlePotentialSnapshotErrors(this._environment, s.missingRequiredFields, s.relayResolverErrors);
}
});
} else {
if (snapshot.missingRequiredFields) {
handlePotentialSnapshotErrors(
this._environment,
snapshot.missingRequiredFields,
snapshot.relayResolverErrors,
);
}
}
}
}
11 changes: 10 additions & 1 deletion src/QueryFetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
OperationDescriptor,
GraphQLTaggedNode,
Variables,
handlePotentialSnapshotErrors,
} from 'relay-runtime';
import { Fetcher, fetchResolver } from './FetchResolver';
import { FetchPolicy, RenderProps, QueryOptions, Options } from './RelayHooksTypes';
Expand Down Expand Up @@ -203,10 +204,18 @@ export class QueryFetcher<TOperationType extends OperationType = OperationType>

resolveResult(): void {
const { error, isLoading } = this.fetcher.getData();
const snapshot: any = this.snapshot;
if (snapshot && snapshot.missingRequiredFields) {
handlePotentialSnapshotErrors(
this.environment,
snapshot.missingRequiredFields,
snapshot.relayResolverErrors,
);
}
this.result = {
retry: this.retry,
error,
data: this.snapshot ? this.snapshot.data : null,
data: snapshot ? snapshot.data : null,
isLoading,
};
}
Expand Down

0 comments on commit 33ee473

Please sign in to comment.