Skip to content

Commit 05b773a

Browse files
captbaritonefacebook-github-bot
authored andcommitted
Include interfaces in weak type resolver definitions
Reviewed By: tyao1 Differential Revision: D53070317 fbshipit-source-id: aa22830fc8b1f3d274ebedfd66ffcafe5150cc70
1 parent 71b6560 commit 05b773a

File tree

4 files changed

+368
-13
lines changed

4 files changed

+368
-13
lines changed

compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/resolver_returns_interface_of_all_weak_model_type.expected

Lines changed: 339 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,343 @@ interface IPerson {
5656
name: String
5757
}
5858
==================================== OUTPUT ===================================
59-
✖︎ No types implement the client interface IPerson. Interfaces returned by a @RelayResolver must have at least one concrete implementation.
59+
//- __generated__/Admin____relay_model_instance.graphql.js
60+
/**
61+
* <auto-generated> SignedSource<<523d097198aa2ffa2a1209e24ac2a337>>
62+
* @flow
63+
* @lightSyntaxTransform
64+
* @nogrep
65+
*/
66+
67+
/* eslint-disable */
68+
69+
'use strict';
70+
71+
/*::
72+
import type { Fragment, ReaderFragment } from 'relay-runtime';
73+
import type { Admin } from "AdminTypeResolvers";
74+
import type { FragmentType } from "relay-runtime";
75+
declare export opaque type Admin____relay_model_instance$fragmentType: FragmentType;
76+
export type Admin____relay_model_instance$data = {|
77+
+__relay_model_instance: Admin,
78+
+$fragmentType: Admin____relay_model_instance$fragmentType,
79+
|};
80+
export type Admin____relay_model_instance$key = {
81+
+$data?: Admin____relay_model_instance$data,
82+
+$fragmentSpreads: Admin____relay_model_instance$fragmentType,
83+
...
84+
};
85+
*/
86+
87+
var node/*: ReaderFragment*/ = {
88+
"argumentDefinitions": [],
89+
"kind": "Fragment",
90+
"metadata": null,
91+
"name": "Admin____relay_model_instance",
92+
"selections": [
93+
{
94+
"kind": "ClientExtension",
95+
"selections": [
96+
{
97+
"alias": null,
98+
"args": null,
99+
"kind": "ScalarField",
100+
"name": "__relay_model_instance",
101+
"storageKey": null
102+
}
103+
]
104+
}
105+
],
106+
"type": "Admin",
107+
"abstractKey": null
108+
};
109+
110+
module.exports = ((node/*: any*/)/*: Fragment<
111+
Admin____relay_model_instance$fragmentType,
112+
Admin____relay_model_instance$data,
113+
>*/);
114+
115+
//- __generated__/QueryComponentQuery.graphql.js
116+
/**
117+
* <auto-generated> SignedSource<<d546c63935d1f27af7720a9906ad8f3c>>
118+
* @flow
119+
* @lightSyntaxTransform
120+
* @nogrep
121+
*/
122+
123+
/* eslint-disable */
124+
125+
'use strict';
126+
127+
/*::
128+
import type { ClientRequest, ClientQuery } from 'relay-runtime';
129+
import {person as queryPersonResolverType} from "QueryResolvers";
130+
// Type assertion validating that `queryPersonResolverType` resolver is correctly implemented.
131+
// A type error here indicates that the type signature of the resolver module is incorrect.
132+
(queryPersonResolverType: () => ?Query__person$normalization);
133+
import type { Query__person$normalization } from "Query__person$normalization.graphql";
134+
export type QueryComponentQuery$variables = {||};
135+
export type QueryComponentQuery$data = {|
136+
+person: ?{|
137+
+name: ?string,
138+
|},
139+
|};
140+
export type QueryComponentQuery = {|
141+
response: QueryComponentQuery$data,
142+
variables: QueryComponentQuery$variables,
143+
|};
144+
*/
145+
146+
var node/*: ClientRequest*/ = (function(){
147+
var v0 = [
148+
{
149+
"alias": null,
150+
"args": null,
151+
"kind": "ScalarField",
152+
"name": "name",
153+
"storageKey": null
154+
}
155+
],
156+
v1 = {
157+
"kind": "InlineFragment",
158+
"selections": (v0/*: any*/),
159+
"type": "Admin",
160+
"abstractKey": null
161+
},
162+
v2 = {
163+
"kind": "InlineFragment",
164+
"selections": (v0/*: any*/),
165+
"type": "User",
166+
"abstractKey": null
167+
};
168+
return {
169+
"fragment": {
170+
"argumentDefinitions": [],
171+
"kind": "Fragment",
172+
"metadata": {
173+
"hasClientEdges": true
174+
},
175+
"name": "QueryComponentQuery",
176+
"selections": [
177+
{
178+
"kind": "ClientEdgeToClientObject",
179+
"concreteType": null,
180+
"backingField": {
181+
"alias": null,
182+
"args": null,
183+
"fragment": null,
184+
"kind": "RelayResolver",
185+
"name": "person",
186+
"resolverModule": require('QueryResolvers').person,
187+
"path": "person",
188+
"normalizationInfo": {
189+
"concreteType": null,
190+
"plural": false,
191+
"normalizationNode": require('Query__person$normalization.graphql')
192+
}
193+
},
194+
"linkedField": {
195+
"alias": null,
196+
"args": null,
197+
"concreteType": null,
198+
"kind": "LinkedField",
199+
"name": "person",
200+
"plural": false,
201+
"selections": [
202+
(v1/*: any*/),
203+
(v2/*: any*/)
204+
],
205+
"storageKey": null
206+
}
207+
}
208+
],
209+
"type": "Query",
210+
"abstractKey": null
211+
},
212+
"kind": "Request",
213+
"operation": {
214+
"argumentDefinitions": [],
215+
"kind": "Operation",
216+
"name": "QueryComponentQuery",
217+
"selections": [
218+
{
219+
"kind": "ClientEdgeToClientObject",
220+
"backingField": {
221+
"name": "person",
222+
"args": null,
223+
"kind": "RelayResolver",
224+
"storageKey": null,
225+
"isOutputType": true,
226+
"resolverInfo": {
227+
"resolverFunction": require('QueryResolvers').person,
228+
"rootFragment": null
229+
}
230+
},
231+
"linkedField": {
232+
"alias": null,
233+
"args": null,
234+
"concreteType": null,
235+
"kind": "LinkedField",
236+
"name": "person",
237+
"plural": false,
238+
"selections": [
239+
{
240+
"alias": null,
241+
"args": null,
242+
"kind": "ScalarField",
243+
"name": "__typename",
244+
"storageKey": null
245+
},
246+
(v1/*: any*/),
247+
(v2/*: any*/)
248+
],
249+
"storageKey": null
250+
}
251+
}
252+
]
253+
},
254+
"params": {
255+
"cacheID": "0ce65d8a9b6587e620fd0d3e136997d6",
256+
"id": null,
257+
"metadata": {},
258+
"name": "QueryComponentQuery",
259+
"operationKind": "query",
260+
"text": null
261+
}
262+
};
263+
})();
264+
265+
(node/*: any*/).hash = "cc7b67152b1dce33f04a61bea084084f";
266+
267+
module.exports = ((node/*: any*/)/*: ClientQuery<
268+
QueryComponentQuery$variables,
269+
QueryComponentQuery$data,
270+
>*/);
271+
272+
//- __generated__/Query__person$normalization.graphql.js
273+
/**
274+
* <auto-generated> SignedSource<<d9cc618b0d62a13fa7de204a0d2f430a>>
275+
* @flow
276+
* @lightSyntaxTransform
277+
* @nogrep
278+
*/
279+
280+
/* eslint-disable */
281+
282+
'use strict';
283+
284+
/*::
285+
import type { NormalizationSplitOperation } from 'relay-runtime';
286+
287+
import type { Admin } from "AdminTypeResolvers";
288+
import type { User } from "UserTypeResolvers";
289+
export type Query__person$normalization = {|
290+
+__typename: "Admin",
291+
+__relay_model_instance: Admin,
292+
|} | {|
293+
+__typename: "User",
294+
+__relay_model_instance: User,
295+
|};
296+
297+
*/
298+
299+
var node/*: NormalizationSplitOperation*/ = (function(){
300+
var v0 = [
301+
{
302+
"alias": null,
303+
"args": null,
304+
"kind": "ScalarField",
305+
"name": "__relay_model_instance",
306+
"storageKey": null
307+
},
308+
{
309+
"alias": null,
310+
"args": null,
311+
"kind": "ScalarField",
312+
"name": "__typename",
313+
"storageKey": null
314+
}
315+
];
316+
return {
317+
"kind": "SplitOperation",
318+
"metadata": {},
319+
"name": "Query__person$normalization",
320+
"selections": [
321+
{
322+
"kind": "ClientExtension",
323+
"selections": [
324+
{
325+
"kind": "InlineFragment",
326+
"selections": (v0/*: any*/),
327+
"type": "Admin",
328+
"abstractKey": null
329+
},
330+
{
331+
"kind": "InlineFragment",
332+
"selections": (v0/*: any*/),
333+
"type": "User",
334+
"abstractKey": null
335+
}
336+
]
337+
}
338+
]
339+
};
340+
})();
341+
342+
module.exports = node;
343+
344+
//- __generated__/User____relay_model_instance.graphql.js
345+
/**
346+
* <auto-generated> SignedSource<<9a188c26688bb46f65ed80df4ae938c3>>
347+
* @flow
348+
* @lightSyntaxTransform
349+
* @nogrep
350+
*/
351+
352+
/* eslint-disable */
353+
354+
'use strict';
355+
356+
/*::
357+
import type { Fragment, ReaderFragment } from 'relay-runtime';
358+
import type { User } from "UserTypeResolvers";
359+
import type { FragmentType } from "relay-runtime";
360+
declare export opaque type User____relay_model_instance$fragmentType: FragmentType;
361+
export type User____relay_model_instance$data = {|
362+
+__relay_model_instance: User,
363+
+$fragmentType: User____relay_model_instance$fragmentType,
364+
|};
365+
export type User____relay_model_instance$key = {
366+
+$data?: User____relay_model_instance$data,
367+
+$fragmentSpreads: User____relay_model_instance$fragmentType,
368+
...
369+
};
370+
*/
371+
372+
var node/*: ReaderFragment*/ = {
373+
"argumentDefinitions": [],
374+
"kind": "Fragment",
375+
"metadata": null,
376+
"name": "User____relay_model_instance",
377+
"selections": [
378+
{
379+
"kind": "ClientExtension",
380+
"selections": [
381+
{
382+
"alias": null,
383+
"args": null,
384+
"kind": "ScalarField",
385+
"name": "__relay_model_instance",
386+
"storageKey": null
387+
}
388+
]
389+
}
390+
],
391+
"type": "User",
392+
"abstractKey": null
393+
};
60394

61-
schema-extensions/extension.graphql:1:11
62-
1 │ interface IPerson {
63-
│ ^^^^^^^
64-
2 │ name: String
395+
module.exports = ((node/*: any*/)/*: Fragment<
396+
User____relay_model_instance$fragmentType,
397+
User____relay_model_instance$data,
398+
>*/);

compiler/crates/relay-docblock/src/docblock_ir.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,13 +304,18 @@ fn parse_weak_object_ir(
304304
parse_options: &ParseOptions<'_>,
305305
) -> DiagnosticsResult<WeakObjectIr> {
306306
// Validate that the right hand side of the @RelayResolver field is a valid identifier
307-
let identifier = if parse_options
307+
let (identifier, implements_interfaces) = if parse_options
308308
.enable_interface_output_type
309309
.is_fully_enabled()
310310
{
311-
extract_identifier(relay_resolver_field)?
311+
let type_str = relay_resolver_field.value;
312+
parse_identifier_and_implements_interfaces(
313+
type_str.item.lookup(),
314+
type_str.location.source_location(),
315+
type_str.location.span().start,
316+
)?
312317
} else {
313-
assert_only_identifier(relay_resolver_field)?
318+
(assert_only_identifier(relay_resolver_field)?, vec![])
314319
};
315320

316321
Ok(WeakObjectIr {
@@ -320,6 +325,7 @@ fn parse_weak_object_ir(
320325
hack_source,
321326
deprecated: fields.remove(&AllowedFieldName::DeprecatedField),
322327
location,
328+
implements_interfaces,
323329
source_hash,
324330
})
325331
}

0 commit comments

Comments
 (0)