Skip to content

Commit

Permalink
Allow @required with client-edges fields
Browse files Browse the repository at this point in the history
Summary: This diffs allows adding required and client edge.

Reviewed By: captbaritone

Differential Revision: D37187697

fbshipit-source-id: 5f2625b8f4fa3d9792442d9383d8cd3d4ba96272
  • Loading branch information
alunyov authored and facebook-github-bot committed Jul 8, 2022
1 parent ab8e59f commit d117221
Show file tree
Hide file tree
Showing 9 changed files with 459 additions and 57 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
==================================== INPUT ====================================
# expected-to-throw

fragment relayResolverWithRequiredClientEdge_best_friend_resolver on User {
actor_key
}
Expand All @@ -22,11 +20,307 @@ extend type User {
import_path: "./foo/bar/baz/BestFriendResolver.js"
)
}
==================================== ERROR ====================================
✖︎ Unexpected directive on Client Edge field. The `@required` directive is not currently supported on fields backed by Client Edges.
==================================== OUTPUT ===================================
{
"fragment": {
"argumentDefinitions": [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "id"
}
],
"kind": "Fragment",
"metadata": null,
"name": "ClientEdgeQuery_relayResolverWithRequiredClientEdgeQuery_me__best_friend",
"selections": [
{
"alias": null,
"args": [
{
"kind": "Variable",
"name": "id",
"variableName": "id"
}
],
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"args": null,
"kind": "FragmentSpread",
"name": "RefetchableClientEdgeQuery_relayResolverWithRequiredClientEdgeQuery_me__best_friend"
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "id"
}
],
"kind": "Operation",
"name": "ClientEdgeQuery_relayResolverWithRequiredClientEdgeQuery_me__best_friend",
"selections": [
{
"alias": null,
"args": [
{
"kind": "Variable",
"name": "id",
"variableName": "id"
}
],
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
}
],
"type": "User",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "1abebb591e62d121570c709a0e09a29c",
"id": null,
"metadata": {},
"name": "ClientEdgeQuery_relayResolverWithRequiredClientEdgeQuery_me__best_friend",
"operationKind": "query",
"text": null
}
}

QUERY:

query ClientEdgeQuery_relayResolverWithRequiredClientEdgeQuery_me__best_friend(
$id: ID!
) {
node(id: $id) {
__typename
...RefetchableClientEdgeQuery_relayResolverWithRequiredClientEdgeQuery_me__best_friend
id
}
}

fragment RefetchableClientEdgeQuery_relayResolverWithRequiredClientEdgeQuery_me__best_friend on User {
name
id
}


{
"fragment": {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": {
"hasClientEdges": true
},
"name": "relayResolverWithRequiredClientEdgeQuery",
"selections": [
{
"alias": null,
"args": null,
"concreteType": "User",
"kind": "LinkedField",
"name": "me",
"plural": false,
"selections": [
{
"kind": "ClientEdgeToServerObject",
"operation": require('ClientEdgeQuery_relayResolverWithRequiredClientEdgeQuery_me__best_friend.graphql'),
"backingField": {
"kind": "RequiredField",
"field": {
"alias": null,
"args": null,
"fragment": {
"args": null,
"kind": "FragmentSpread",
"name": "relayResolverWithRequiredClientEdge_best_friend_resolver"
},
"kind": "RelayResolver",
"name": "best_friend",
"resolverModule": require('BestFriendResolver'),
"path": "me.best_friend"
},
"action": "THROW",
"path": "me.best_friend"
},
"linkedField": {
"kind": "RequiredField",
"field": {
"alias": null,
"args": null,
"concreteType": "User",
"kind": "LinkedField",
"name": "best_friend",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
}
],
"storageKey": null
},
"action": "THROW",
"path": "me.best_friend"
}
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [],
"kind": "Operation",
"name": "relayResolverWithRequiredClientEdgeQuery",
"selections": [
{
"alias": null,
"args": null,
"concreteType": "User",
"kind": "LinkedField",
"name": "me",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "actor_key",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "c38847c6495c061f05952cde25b648e7",
"id": null,
"metadata": {},
"name": "relayResolverWithRequiredClientEdgeQuery",
"operationKind": "query",
"text": null
}
}

QUERY:

query relayResolverWithRequiredClientEdgeQuery {
me {
...relayResolverWithRequiredClientEdge_best_friend_resolver
id
}
}

fragment relayResolverWithRequiredClientEdge_best_friend_resolver on User {
actor_key
}

relay-resolver-with-required-client-edge.graphql:9:28
8 │ me {
9 │ best_friend @waterfall @required(action: THROW) {
│ ^^^^^^^^^
10 │ name

{
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": {
"refetch": {
"connection": null,
"fragmentPathInResult": [
"node"
],
"operation": require('ClientEdgeQuery_relayResolverWithRequiredClientEdgeQuery_me__best_friend.graphql'),
"identifierField": "id"
}
},
"name": "RefetchableClientEdgeQuery_relayResolverWithRequiredClientEdgeQuery_me__best_friend",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
}
],
"type": "User",
"abstractKey": null
}

{
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "relayResolverWithRequiredClientEdge_best_friend_resolver",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "actor_key",
"storageKey": null
}
],
"type": "User",
"abstractKey": null
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# expected-to-throw

fragment relayResolverWithRequiredClientEdge_best_friend_resolver on User {
actor_key
}
Expand Down
14 changes: 13 additions & 1 deletion compiler/crates/relay-transforms/src/client_edges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@

use crate::refetchable_fragment::RefetchableFragment;
use crate::refetchable_fragment::REFETCHABLE_NAME;
use crate::RequiredMetadataDirective;
use crate::ValidationMessage;
use crate::REQUIRED_DIRECTIVE_NAME;
use graphql_syntax::OperationKind;
use intern::string_key::Intern;
use intern::string_key::StringKey;
Expand Down Expand Up @@ -298,10 +300,20 @@ impl<'program, 'sc> ClientEdgesTransform<'program, 'sc> {
return self.default_transform_linked_field(field);
}

let allowed_dirctive_names = [
*CLIENT_EDGE_WATERFALL_DIRECTIVE_NAME,
*REQUIRED_DIRECTIVE_NAME,
RequiredMetadataDirective::directive_name(),
];

let other_directives = field
.directives
.iter()
.filter(|directive| directive.name() != *CLIENT_EDGE_WATERFALL_DIRECTIVE_NAME)
.filter(|directive| {
!allowed_dirctive_names
.iter()
.any(|item| directive.name() == *item)
})
.collect::<Vec<_>>();

for directive in other_directives {
Expand Down
Loading

0 comments on commit d117221

Please sign in to comment.