Skip to content

Commit 10172f1

Browse files
tyao1meta-codesync[bot]
authored andcommitted
Don't emit has_s2c_resolvers flag for Query-rooted resolvers
Reviewed By: leealison Differential Revision: D102387509 fbshipit-source-id: 13d701181a267e8cc2dcdd5fa769056354db600d
1 parent 54f210d commit 10172f1

4 files changed

Lines changed: 221 additions & 4 deletions

File tree

compiler/crates/relay-codegen/src/build_ast.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -958,13 +958,15 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> {
958958
resolver_metadata: &RelayResolverMetadata,
959959
inline_fragment: Option<Primitive>,
960960
) -> Primitive {
961-
// Detect S2C resolvers: client extension field on a server type with a
962-
// rootFragment. Only relevant for exec-time resolver queries, where the
963-
// runtime needs to know whether to enable network normalization for S2C.
961+
// Detect S2C resolvers: client extension field on a non-Query server
962+
// type with a rootFragment. Query-rooted resolvers don't traverse a
963+
// server-to-client boundary, so they don't need network normalization.
964+
// Only relevant for exec-time resolver queries.
964965
if !context.has_server_to_client_resolvers && context.has_exec_time_resolvers_directive {
965966
let field = resolver_metadata.field(self.schema);
966967
if let Some(parent_type) = field.parent_type
967968
&& !self.schema.is_extension_type(parent_type)
969+
&& Some(parent_type) != self.schema.query_type()
968970
&& get_resolver_fragment_dependency_name(field).is_some()
969971
{
970972
context.has_server_to_client_resolvers = true;
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
==================================== INPUT ====================================
2+
//- FooQuery.js
3+
graphql`query FooQuery @exec_time_resolvers {
4+
greeting
5+
}`
6+
7+
//- Query_greeting.js
8+
/**
9+
* @relayField Query.greeting: RelayResolverValue
10+
* @rootFragment QueryGreetingFragment
11+
*/
12+
graphql`fragment QueryGreetingFragment on Query {
13+
hello
14+
}`
15+
16+
//- relay.config.json
17+
{
18+
"language": "flow",
19+
"jsModuleFormat": "haste",
20+
"schema": "schema.graphql",
21+
"featureFlags": {
22+
"enable_exec_time_resolvers_directive": true
23+
}
24+
}
25+
26+
//- schema.graphql
27+
type Query { hello: String }
28+
==================================== OUTPUT ===================================
29+
//-++ __generated__/FooQuery.graphql.js
30+
/**
31+
* <auto-generated> SignedSource<<27366b7391f331938946b7c4c0e19857>>
32+
* @flow
33+
* @lightSyntaxTransform
34+
*/
35+
36+
/* eslint-disable */
37+
38+
'use strict';
39+
40+
/*::
41+
import type { ConcreteRequest, Query } from 'relay-runtime';
42+
import type { QueryGreetingFragment$key } from "QueryGreetingFragment.graphql";
43+
import {greeting as queryGreetingResolverType} from "Query_greeting";
44+
// Type assertion validating that `queryGreetingResolverType` resolver is correctly implemented.
45+
// A type error here indicates that the type signature of the resolver module is incorrect.
46+
(queryGreetingResolverType as (
47+
rootKey: QueryGreetingFragment$key,
48+
) => ?unknown);
49+
export type FooQuery$variables = {||};
50+
export type FooQuery$data = {|
51+
+greeting: ?ReturnType<typeof queryGreetingResolverType>,
52+
|};
53+
export type FooQuery = {|
54+
response: FooQuery$data,
55+
variables: FooQuery$variables,
56+
|};
57+
*/
58+
59+
import QueryGreetingFragment$normalization from 'QueryGreetingFragment$normalization.graphql';
60+
import {greeting as queryGreetingResolver} from 'Query_greeting';
61+
62+
var node/*: ConcreteRequest*/ = {
63+
"fragment": {
64+
"argumentDefinitions": [],
65+
"kind": "Fragment",
66+
"metadata": null,
67+
"name": "FooQuery",
68+
"selections": [
69+
{
70+
"alias": null,
71+
"args": null,
72+
"fragment": {
73+
"args": null,
74+
"kind": "FragmentSpread",
75+
"name": "QueryGreetingFragment"
76+
},
77+
"kind": "RelayResolver",
78+
"name": "greeting",
79+
"resolverModule": queryGreetingResolver,
80+
"path": "greeting"
81+
}
82+
],
83+
"type": "Query",
84+
"abstractKey": null
85+
},
86+
"kind": "Request",
87+
"operation": {
88+
"argumentDefinitions": [],
89+
"kind": "Operation",
90+
"name": "FooQuery",
91+
"selections": [
92+
{
93+
"name": "greeting",
94+
"args": null,
95+
"kind": "RelayResolver",
96+
"storageKey": null,
97+
"isOutputType": true,
98+
"resolverInfo": {
99+
"resolverFunction": queryGreetingResolver,
100+
"rootFragment": QueryGreetingFragment$normalization
101+
}
102+
}
103+
],
104+
"use_exec_time_resolvers": true
105+
},
106+
"params": {
107+
"cacheID": "1a49120fcd60bb1f02d7ac09b3cbd144",
108+
"id": null,
109+
"metadata": {},
110+
"name": "FooQuery",
111+
"operationKind": "query",
112+
"text": "query FooQuery {\n ...QueryGreetingFragment\n}\n\nfragment QueryGreetingFragment on Query {\n hello\n}\n"
113+
}
114+
};
115+
116+
(node/*:: as any*/).hash = "1bbdafc092e9f15dc07de12332609865";
117+
118+
export default ((node/*:: as any*/)/*:: as Query<
119+
FooQuery$variables,
120+
FooQuery$data,
121+
>*/);
122+
123+
//-++ __generated__/QueryGreetingFragment.graphql.js
124+
/**
125+
* <auto-generated> SignedSource<<3a769eb78a23236c375444a2b90ecfc2>>
126+
* @flow
127+
* @lightSyntaxTransform
128+
*/
129+
130+
/* eslint-disable */
131+
132+
'use strict';
133+
134+
/*::
135+
import type { Fragment, ReaderFragment } from 'relay-runtime';
136+
import type { FragmentType } from "relay-runtime";
137+
declare export opaque type QueryGreetingFragment$fragmentType: FragmentType;
138+
export type QueryGreetingFragment$data = {|
139+
+hello: ?string,
140+
+$fragmentType: QueryGreetingFragment$fragmentType,
141+
|};
142+
export type QueryGreetingFragment$key = {
143+
+$data?: QueryGreetingFragment$data,
144+
+$fragmentSpreads: QueryGreetingFragment$fragmentType,
145+
...
146+
};
147+
*/
148+
149+
var node/*: ReaderFragment*/ = {
150+
"argumentDefinitions": [],
151+
"kind": "Fragment",
152+
"metadata": null,
153+
"name": "QueryGreetingFragment",
154+
"selections": [
155+
{
156+
"alias": null,
157+
"args": null,
158+
"kind": "ScalarField",
159+
"name": "hello",
160+
"storageKey": null
161+
}
162+
],
163+
"type": "Query",
164+
"abstractKey": null
165+
};
166+
167+
(node/*:: as any*/).hash = "aa3fc96ab8cde35a05248c52a28974b3";
168+
169+
export default ((node/*:: as any*/)/*:: as Fragment<
170+
QueryGreetingFragment$fragmentType,
171+
QueryGreetingFragment$data,
172+
>*/);
173+
174+
175+
176+
Artifact Map:
177+
Project: default
178+
Type: Mapping
179+
- Source: ExecutableDefinition: FooQuery
180+
Path: __generated__/FooQuery.graphql.js
181+
- Source: ExecutableDefinition: QueryGreetingFragment
182+
Path: __generated__/QueryGreetingFragment.graphql.js
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//- FooQuery.js
2+
graphql`query FooQuery @exec_time_resolvers {
3+
greeting
4+
}`
5+
6+
//- Query_greeting.js
7+
/**
8+
* @relayField Query.greeting: RelayResolverValue
9+
* @rootFragment QueryGreetingFragment
10+
*/
11+
graphql`fragment QueryGreetingFragment on Query {
12+
hello
13+
}`
14+
15+
//- relay.config.json
16+
{
17+
"language": "flow",
18+
"jsModuleFormat": "haste",
19+
"schema": "schema.graphql",
20+
"featureFlags": {
21+
"enable_exec_time_resolvers_directive": true
22+
}
23+
}
24+
25+
//- schema.graphql
26+
type Query { hello: String }

compiler/crates/relay-compiler/tests/relay_compiler_integration_test.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<4df8517645c9600a04e89ad131562609>>
7+
* @generated SignedSource<<98121eafbd62f09e68b191ccfac99807>>
88
*/
99

1010
mod relay_compiler_integration;
@@ -194,6 +194,13 @@ async fn exec_time_resolver_mixed_interface_client_edge_invalid() {
194194
test_fixture(transform_fixture, file!(), "exec_time_resolver_mixed_interface_client_edge.invalid.input", "relay_compiler_integration/fixtures/exec_time_resolver_mixed_interface_client_edge.invalid.expected", input, expected).await;
195195
}
196196

197+
#[tokio::test]
198+
async fn exec_time_resolver_query_root_no_flag() {
199+
let input = include_str!("relay_compiler_integration/fixtures/exec_time_resolver_query_root_no_flag.input");
200+
let expected = include_str!("relay_compiler_integration/fixtures/exec_time_resolver_query_root_no_flag.expected");
201+
test_fixture(transform_fixture, file!(), "exec_time_resolver_query_root_no_flag.input", "relay_compiler_integration/fixtures/exec_time_resolver_query_root_no_flag.expected", input, expected).await;
202+
}
203+
197204
#[tokio::test]
198205
async fn exec_time_resolver_server_to_client_has_flag() {
199206
let input = include_str!("relay_compiler_integration/fixtures/exec_time_resolver_server_to_client_has_flag.input");

0 commit comments

Comments
 (0)