5
5
* LICENSE file in the root directory of this source tree.
6
6
*/
7
7
8
+ use std:: str:: FromStr ;
9
+
10
+ use :: intern:: string_key:: StringKey ;
8
11
use common:: ArgumentName ;
9
12
use common:: Diagnostic ;
10
13
use common:: DiagnosticsResult ;
@@ -16,18 +19,21 @@ use graphql_ir::ConstantValue;
16
19
use graphql_ir:: OperationDefinition ;
17
20
use graphql_ir:: OperationDefinitionName ;
18
21
use graphql_ir:: Program ;
22
+ use graphql_ir:: Selection ;
19
23
use graphql_ir:: Transformed ;
20
24
use graphql_ir:: Transformer ;
21
25
use graphql_ir:: Value ;
22
26
use graphql_syntax:: OperationKind ;
23
27
use intern:: string_key:: Intern ;
28
+ use itertools:: Itertools ;
24
29
use lazy_static:: lazy_static;
25
30
use thiserror:: Error ;
26
31
27
32
use crate :: create_metadata_directive;
28
33
29
34
lazy_static ! {
30
35
static ref LIVE_QUERY_DIRECTIVE_NAME : DirectiveName = DirectiveName ( "live_query" . intern( ) ) ;
36
+ static ref LIVE_DIRECTIVE_NAME : DirectiveName = DirectiveName ( "live" . intern( ) ) ;
31
37
static ref LIVE_METADATA_KEY : ArgumentName = ArgumentName ( "live" . intern( ) ) ;
32
38
static ref POLLING_INTERVAL_ARG : ArgumentName = ArgumentName ( "polling_interval" . intern( ) ) ;
33
39
static ref CONFIG_ID_ARG : ArgumentName = ArgumentName ( "config_id" . intern( ) ) ;
@@ -62,6 +68,7 @@ impl Transformer for GenerateLiveQueryMetadata {
62
68
) -> Transformed < OperationDefinition > {
63
69
match operation. kind {
64
70
OperationKind :: Query => {
71
+ let mut next_directives = operation. directives . clone ( ) ;
65
72
let live_query_directive = operation. directives . named ( * LIVE_QUERY_DIRECTIVE_NAME ) ;
66
73
if let Some ( live_query_directive) = live_query_directive {
67
74
let polling_interval =
@@ -78,10 +85,16 @@ impl Transformer for GenerateLiveQueryMetadata {
78
85
return Transformed :: Keep ;
79
86
}
80
87
81
- let mut next_directives = operation. directives . clone ( ) ;
88
+ if polling_interval. is_some ( ) && config_id. is_some ( ) {
89
+ self . errors . push ( Diagnostic :: error (
90
+ LiveQueryTransformValidationMessage :: InvalidConfig {
91
+ query_name : operation. name . item ,
92
+ } ,
93
+ live_query_directive. location ,
94
+ ) ) ;
95
+ return Transformed :: Keep ;
96
+ }
82
97
83
- // I'm porting JS logic here. Not sure if the case where
84
- // polling_interval and config_id both provided handled correctly
85
98
if let Some ( polling_interval) = polling_interval {
86
99
let poll_interval_value = match polling_interval. value . item {
87
100
Value :: Constant ( ConstantValue :: Int ( value) ) => value,
@@ -127,14 +140,41 @@ impl Transformer for GenerateLiveQueryMetadata {
127
140
} ] ) ,
128
141
) ) ;
129
142
}
130
10000
td>
-
131
- Transformed :: Replace ( OperationDefinition {
132
- directives : next_directives,
133
- ..operation. clone ( )
134
- } )
135
143
} else {
136
- Transformed :: Keep
144
+ // Look for `@live` query root fields
145
+ let live_directives = operation
146
+ . selections
147
+ . iter ( )
148
+ . filter ( |sel| !matches ! ( sel, Selection :: Condition ( _) ) )
149
+ . filter_map ( |sel| sel. directives ( ) . named ( * LIVE_DIRECTIVE_NAME ) )
150
+ . collect :: < Vec < _ > > ( ) ;
151
+
152
+ if live_directives. is_empty ( ) {
153
+ return Transformed :: Keep ;
154
+ }
155
+ // We allow multiple `@live` selections in a query but don't allow multiple `config_id`s. Because
156
+ // it confuses `method` header formation. `config_id` on `@live` is only used for `@live_query`
157
+ // use case migration, which translates into exactly 1 `@live` selection.
158
+ let config_id = live_directives
159
+ . iter ( )
160
+ . filter_map ( |dir| dir. arguments . named ( * CONFIG_ID_ARG ) )
161
+ . at_most_one ( )
162
+ . unwrap ( )
163
+ . and_then ( |arg| arg. value . item . get_string_literal ( ) )
164
+ . unwrap_or_else ( || StringKey :: from_str ( "" ) . unwrap ( ) ) ;
165
+
166
+ next_directives. push ( create_metadata_directive (
167
+ * LIVE_METADATA_KEY ,
168
+ ConstantValue :: Object ( vec ! [ ConstantArgument {
169
+ name: WithLocation :: generated( * CONFIG_ID_ARG ) ,
170
+ value: WithLocation :: generated( ConstantValue :: String ( config_id) ) ,
171
+ } ] ) ,
172
+ ) ) ;
137
173
}
174
+ Transformed :: Replace ( OperationDefinition {
175
+ directives : next_directives,
176
+ ..operation. clone ( )
177
+ } )
138
178
}
139
179
_ => Transformed :: Keep ,
140
180
}
@@ -149,6 +189,11 @@ enum LiveQueryTransformValidationMessage {
149
189
) ]
150
190
MissingConfig { query_name : OperationDefinitionName } ,
151
191
192
+ #[ error(
193
+ "'polling_interval' and 'config_id' cannot both be present in @live_query for root field {query_name}"
194
+ ) ]
195
+ InvalidConfig { query_name : OperationDefinitionName } ,
196
+
152
197
#[ error(
153
198
"Expected the 'polling_interval' argument to @live_query to be a literal number for root field {query_name}"
154
199
) ]
0 commit comments