@@ -10,23 +10,70 @@ use std::sync::Arc;
10
10
use common:: DiagnosticsResult ;
11
11
use common:: NamedItem ;
12
12
use docblock_shared:: RELAY_RESOLVER_DIRECTIVE_NAME ;
13
+ use graphql_ir:: associated_data_impl;
14
+ use graphql_ir:: ExecutableDefinition ;
15
+ use graphql_ir:: FragmentDefinition ;
16
+ use graphql_ir:: FragmentDefinitionName ;
13
17
use graphql_ir:: OperationDefinition ;
14
18
use graphql_ir:: OperationDefinitionName ;
15
19
use graphql_ir:: Program ;
16
20
use graphql_syntax:: OperationKind ;
17
21
use intern:: string_key:: Intern ;
22
+ use rustc_hash:: FxHashSet ;
23
+ use schema:: SDLSchema ;
18
24
19
- use crate :: generate_relay_resolvers_model_fragments:: directives_with_artifact_source;
20
25
use crate :: get_normalization_operation_name;
21
26
use crate :: get_resolver_fragment_dependency_name;
22
27
use crate :: SplitOperationMetadata ;
23
28
use crate :: RESOLVER_BELONGS_TO_BASE_SCHEMA_DIRECTIVE ;
24
29
30
+ #[ derive( Clone , Debug , PartialEq , Eq , Hash ) ]
31
+ struct IsResolverRootFragment ( ) ;
32
+ associated_data_impl ! ( IsResolverRootFragment ) ;
33
+
25
34
pub fn generate_relay_resolvers_root_fragment_split_operation (
26
35
program : & Program ,
27
36
) -> DiagnosticsResult < Program > {
28
37
let mut operations = vec ! [ ] ;
29
- for field in program. schema . get_fields ( ) {
38
+ for fragment in program. fragments ( ) {
39
+ if IsResolverRootFragment :: find ( & fragment. directives ) . is_some ( ) {
40
+ operations. push ( Arc :: new ( OperationDefinition {
41
+ name : fragment. name . map ( |name| {
42
+ OperationDefinitionName ( get_normalization_operation_name ( name. 0 ) . intern ( ) )
43
+ } ) ,
44
+ type_ : fragment. type_condition ,
45
+ variable_definitions : fragment. variable_definitions . clone ( ) ,
46
+ directives : vec ! [
47
+ SplitOperationMetadata {
48
+ location: fragment. name. location,
49
+ parent_documents: FxHashSet :: from_iter( [ fragment. name. item. into( ) ] ) ,
50
+ derived_from: Some ( fragment. name. item) ,
51
+ raw_response_type_generation_mode: None ,
52
+ }
53
+ . into( ) ,
54
+ ] ,
55
+ selections : fragment. selections . clone ( ) ,
56
+ kind : OperationKind :: Query ,
57
+ } ) ) ;
58
+ }
59
+ }
60
+
61
+ if operations. is_empty ( ) {
62
+ Ok ( program. clone ( ) )
63
+ } else {
64
+ let mut next_program = program. clone ( ) ;
65
+
66
+ for operation in operations {
67
+ next_program. insert_operation ( operation)
68
+ }
69
+
70
+ Ok ( next_program)
71
+ }
72
+ }
73
+
74
+ fn get_resolver_root_fragment_names ( schema : & SDLSchema ) -> FxHashSet < FragmentDefinitionName > {
75
+ let mut names = FxHashSet :: default ( ) ;
76
+ for field in schema. get_fields ( ) {
30
77
if !field. is_extension
31
78
|| field
32
79
. directives
@@ -40,47 +87,38 @@ pub fn generate_relay_resolvers_root_fragment_split_operation(
40
87
continue ;
41
88
}
42
89
43
- let root_fragment_name = get_resolver_fragment_dependency_name ( field) ;
44
- if root_fragment_name. is_none ( ) {
45
- continue ;
90
+ if let Some ( root_fragment_name) = get_resolver_fragment_dependency_name ( field) {
91
+ names. insert ( root_fragment_name) ;
46
92
}
47
-
48
- let root_fragment = program. fragment ( root_fragment_name. unwrap ( ) ) . unwrap ( ) ;
49
- let operation_name = root_fragment
50
- . name
51
- . map ( |name| OperationDefinitionName ( get_normalization_operation_name ( name. 0 ) . intern ( ) ) ) ;
52
-
53
- let mut directives = directives_with_artifact_source ( field) ;
54
- directives. push (
55
- SplitOperationMetadata {
56
- location : root_fragment. name . location ,
57
- parent_documents : Default :: default ( ) ,
58
- derived_from : Some ( root_fragment. name . item ) ,
59
- raw_response_type_generation_mode : None ,
60
- }
61
- . into ( ) ,
62
- ) ;
63
- let operation = OperationDefinition {
64
- name : operation_name,
65
- type_ : root_fragment. type_condition ,
66
- variable_definitions : root_fragment. variable_definitions . clone ( ) ,
67
- directives,
68
- selections : root_fragment. selections . clone ( ) ,
69
- kind : OperationKind :: Query ,
70
- } ;
71
-
72
- operations. push ( Arc :: new ( operation) )
73
93
}
94
+ names
95
+ }
74
96
75
- if operations. is_empty ( ) {
76
- Ok ( program. clone ( ) )
77
- } else {
78
- let mut next_program = program. clone ( ) ;
79
-
80
- for operation in operations {
81
- next_program. insert_operation ( operation)
82
- }
83
-
84
- Ok ( next_program)
85
- }
97
+ /// Adds a directive on all `FragmentDefinition`s in IR that are marked as a `@rootFragment`
98
+ /// for any resolver backed field in the schema (but not base schema)
99
+ pub fn annotate_resolver_root_fragments (
100
+ schema : & SDLSchema ,
101
+ ir : Vec < ExecutableDefinition > ,
102
+ ) -> Vec < ExecutableDefinition > {
103
+ let resolver_root_fragment_names = get_resolver_root_fragment_names ( schema) ;
104
+ ir. into_iter ( )
105
+ . map ( |def| {
106
+ if let ExecutableDefinition :: Fragment ( ref fragment) = def {
107
+ return if resolver_root_fragment_names. contains ( & fragment. name . item ) {
108
+ ExecutableDefinition :: Fragment ( FragmentDefinition {
109
+ directives : fragment
110
+ . directives
111
+ . iter ( )
112
+ . cloned ( )
113
+ . chain ( vec ! [ IsResolverRootFragment ( ) . into( ) ] )
114
+ . collect ( ) ,
115
+ ..fragment. clone ( )
116
+ } )
117
+ } else {
118
+ def
119
+ } ;
120
+ }
121
+ def
122
+ } )
123
+ . collect ( )
86
124
}
0 commit comments