Skip to main content

libgraphql_parser/compat/graphql_parser_v0_4/
from_query.rs

1//! Reverse query conversion: `graphql_parser` v0.4
2//! query `Document` → libgraphql AST.
3
4use crate::ast;
5use crate::compat::graphql_parser_v0_4::helpers::gp_directives_to_ast;
6use crate::compat::graphql_parser_v0_4::helpers::gp_type_to_ast;
7use crate::compat::graphql_parser_v0_4::helpers::gp_value_to_ast;
8use crate::compat::graphql_parser_v0_4::helpers::FromGpContext;
9
10/// Convert a `graphql_parser` query `Document` to a
11/// libgraphql AST `Document`.
12///
13/// This is the reverse of
14/// `to_graphql_parser_query_ast`. The conversion is
15/// lossy in the same ways as
16/// `from_graphql_parser_schema_ast`.
17///
18/// `graphql_parser` does not support directives on
19/// `VariableDefinition`, so the resulting
20/// `VariableDefinition.directives` will always be
21/// empty.
22///
23/// Byte offsets are 0. Use
24/// `from_graphql_parser_query_ast_with_source` for
25/// accurate byte offsets.
26pub fn from_graphql_parser_query_ast(
27    doc: &graphql_parser::query::Document<
28        'static,
29        String,
30    >,
31) -> ast::Document<'static> {
32    let ctx = FromGpContext::without_source();
33    from_gp_query_impl(doc, &ctx)
34}
35
36/// Like `from_graphql_parser_query_ast`, but computes
37/// byte offsets from the source text for accurate
38/// `ByteSpan` byte offset values.
39pub fn from_graphql_parser_query_ast_with_source(
40    doc: &graphql_parser::query::Document<
41        'static,
42        String,
43    >,
44    source: &str,
45) -> ast::Document<'static> {
46    let ctx = FromGpContext::with_source(source);
47    from_gp_query_impl(doc, &ctx)
48}
49
50fn from_gp_query_impl(
51    doc: &graphql_parser::query::Document<
52        'static,
53        String,
54    >,
55    ctx: &FromGpContext<'_>,
56) -> ast::Document<'static> {
57    let definitions = doc
58        .definitions
59        .iter()
60        .map(|def| {
61            use graphql_parser::query::Definition
62                as GpDef;
63            match def {
64                GpDef::Operation(op) => {
65                    ast::Definition::OperationDefinition(
66                        gp_operation_to_ast(op, ctx),
67                    )
68                },
69                GpDef::Fragment(frag) => {
70                    ast::Definition::FragmentDefinition(
71                        gp_fragment_def_to_ast(
72                            frag, ctx,
73                        ),
74                    )
75                },
76            }
77        })
78        .collect();
79
80    ast::Document {
81        definitions,
82        span: ctx.zero_span(),
83        syntax: None,
84    }
85}
86
87fn gp_selection_set_to_ast(
88    ss: &graphql_parser::query::SelectionSet<
89        'static,
90        String,
91    >,
92    ctx: &FromGpContext<'_>,
93) -> ast::SelectionSet<'static> {
94    ast::SelectionSet {
95        selections: ss
96            .items
97            .iter()
98            .map(|s| gp_selection_to_ast(s, ctx))
99            .collect(),
100        span: ctx.span_from_pos_pair(
101            ss.span.0, ss.span.1,
102        ),
103        syntax: None,
104    }
105}
106
107fn gp_selection_to_ast(
108    sel: &graphql_parser::query::Selection<
109        'static,
110        String,
111    >,
112    ctx: &FromGpContext<'_>,
113) -> ast::Selection<'static> {
114    use graphql_parser::query::Selection as GpSel;
115    match sel {
116        GpSel::Field(field) => {
117            ast::Selection::Field(
118                gp_query_field_to_ast(field, ctx),
119            )
120        },
121        GpSel::FragmentSpread(spread) => {
122            ast::Selection::FragmentSpread(
123                gp_fragment_spread_to_ast(spread, ctx),
124            )
125        },
126        GpSel::InlineFragment(inline) => {
127            ast::Selection::InlineFragment(
128                gp_inline_fragment_to_ast(inline, ctx),
129            )
130        },
131    }
132}
133
134fn gp_query_field_to_ast(
135    field: &graphql_parser::query::Field<
136        'static,
137        String,
138    >,
139    ctx: &FromGpContext<'_>,
140) -> ast::FieldSelection<'static> {
141    let selection_set = if field
142        .selection_set
143        .items
144        .is_empty()
145    {
146        None
147    } else {
148        Some(gp_selection_set_to_ast(
149            &field.selection_set,
150            ctx,
151        ))
152    };
153
154    ast::FieldSelection {
155        alias: field
156            .alias
157            .as_ref()
158            .map(|a| ctx.string_to_name(a)),
159        arguments: field
160            .arguments
161            .iter()
162            .map(|(name, val)| ast::Argument {
163                name: ctx.string_to_name(name),
164                span: ctx.zero_span(),
165                syntax: None,
166                value: gp_value_to_ast(val, ctx),
167            })
168            .collect(),
169        directives: gp_directives_to_ast(
170            &field.directives,
171            ctx,
172        ),
173        name: ctx.string_to_name_at(
174            &field.name,
175            field.position,
176        ),
177        selection_set,
178        span: ctx.span_from_pos(field.position),
179        syntax: None,
180    }
181}
182
183fn gp_fragment_spread_to_ast(
184    spread: &graphql_parser::query::FragmentSpread<
185        'static,
186        String,
187    >,
188    ctx: &FromGpContext<'_>,
189) -> ast::FragmentSpread<'static> {
190    ast::FragmentSpread {
191        directives: gp_directives_to_ast(
192            &spread.directives,
193            ctx,
194        ),
195        name: ctx.string_to_name_at(
196            &spread.fragment_name,
197            spread.position,
198        ),
199        span: ctx.span_from_pos(spread.position),
200        syntax: None,
201    }
202}
203
204fn gp_inline_fragment_to_ast(
205    inline: &graphql_parser::query::InlineFragment<
206        'static,
207        String,
208    >,
209    ctx: &FromGpContext<'_>,
210) -> ast::InlineFragment<'static> {
211    ast::InlineFragment {
212        directives: gp_directives_to_ast(
213            &inline.directives,
214            ctx,
215        ),
216        selection_set: gp_selection_set_to_ast(
217            &inline.selection_set,
218            ctx,
219        ),
220        span: ctx.span_from_pos(inline.position),
221        syntax: None,
222        type_condition: inline
223            .type_condition
224            .as_ref()
225            .map(|tc| {
226                gp_type_condition_to_ast(tc, ctx)
227            }),
228    }
229}
230
231fn gp_type_condition_to_ast(
232    tc: &graphql_parser::query::TypeCondition<
233        'static,
234        String,
235    >,
236    ctx: &FromGpContext<'_>,
237) -> ast::TypeCondition<'static> {
238    let graphql_parser::query::TypeCondition::On(
239        name,
240    ) = tc;
241    ast::TypeCondition {
242        named_type: ctx.string_to_name(name),
243        span: ctx.zero_span(),
244        syntax: None,
245    }
246}
247
248fn gp_variable_def_to_ast(
249    var_def: &graphql_parser::query::VariableDefinition<
250        'static,
251        String,
252    >,
253    ctx: &FromGpContext<'_>,
254) -> ast::VariableDefinition<'static> {
255    ast::VariableDefinition {
256        default_value: var_def
257            .default_value
258            .as_ref()
259            .map(|v| gp_value_to_ast(v, ctx)),
260        description: None,
261        directives: vec![],
262        span: ctx.span_from_pos(var_def.position),
263        syntax: None,
264        var_type: gp_type_to_ast(
265            &var_def.var_type,
266            ctx,
267        ),
268        variable: ctx.string_to_name_at(
269            &var_def.name,
270            var_def.position,
271        ),
272    }
273}
274
275fn gp_fragment_def_to_ast(
276    frag: &graphql_parser::query::FragmentDefinition<
277        'static,
278        String,
279    >,
280    ctx: &FromGpContext<'_>,
281) -> ast::FragmentDefinition<'static> {
282    ast::FragmentDefinition {
283        description: None,
284        directives: gp_directives_to_ast(
285            &frag.directives,
286            ctx,
287        ),
288        name: ctx.string_to_name_at(
289            &frag.name,
290            frag.position,
291        ),
292        selection_set: gp_selection_set_to_ast(
293            &frag.selection_set,
294            ctx,
295        ),
296        span: ctx.span_from_pos(frag.position),
297        syntax: None,
298        type_condition: gp_type_condition_to_ast(
299            &frag.type_condition,
300            ctx,
301        ),
302    }
303}
304
305fn gp_operation_to_ast(
306    op: &graphql_parser::query::OperationDefinition<
307        'static,
308        String,
309    >,
310    ctx: &FromGpContext<'_>,
311) -> ast::OperationDefinition<'static> {
312    use graphql_parser::query::OperationDefinition
313        as GpOp;
314    match op {
315        GpOp::SelectionSet(ss) => {
316            ast::OperationDefinition {
317                description: None,
318                directives: vec![],
319                name: None,
320                operation_kind:
321                    ast::OperationKind::Query,
322                selection_set:
323                    gp_selection_set_to_ast(ss, ctx),
324                shorthand: true,
325                span: ctx.span_from_pos(ss.span.0),
326                syntax: None,
327                variable_definitions: vec![],
328            }
329        },
330        GpOp::Query(query) => {
331            ast::OperationDefinition {
332                description: None,
333                directives: gp_directives_to_ast(
334                    &query.directives,
335                    ctx,
336                ),
337                name: query.name.as_ref().map(|n| {
338                    ctx.string_to_name_at(
339                        n,
340                        query.position,
341                    )
342                }),
343                operation_kind:
344                    ast::OperationKind::Query,
345                selection_set:
346                    gp_selection_set_to_ast(
347                        &query.selection_set,
348                        ctx,
349                    ),
350                shorthand: false,
351                span: ctx
352                    .span_from_pos(query.position),
353                syntax: None,
354                variable_definitions: query
355                    .variable_definitions
356                    .iter()
357                    .map(|vd| {
358                        gp_variable_def_to_ast(vd, ctx)
359                    })
360                    .collect(),
361            }
362        },
363        GpOp::Mutation(mutation) => {
364            ast::OperationDefinition {
365                description: None,
366                directives: gp_directives_to_ast(
367                    &mutation.directives,
368                    ctx,
369                ),
370                name: mutation.name.as_ref().map(|n| {
371                    ctx.string_to_name_at(
372                        n,
373                        mutation.position,
374                    )
375                }),
376                operation_kind:
377                    ast::OperationKind::Mutation,
378                selection_set:
379                    gp_selection_set_to_ast(
380                        &mutation.selection_set,
381                        ctx,
382                    ),
383                shorthand: false,
384                span: ctx.span_from_pos(
385                    mutation.position,
386                ),
387                syntax: None,
388                variable_definitions: mutation
389                    .variable_definitions
390                    .iter()
391                    .map(|vd| {
392                        gp_variable_def_to_ast(vd, ctx)
393                    })
394                    .collect(),
395            }
396        },
397        GpOp::Subscription(sub) => {
398            ast::OperationDefinition {
399                description: None,
400                directives: gp_directives_to_ast(
401                    &sub.directives,
402                    ctx,
403                ),
404                name: sub.name.as_ref().map(|n| {
405                    ctx.string_to_name_at(
406                        n,
407                        sub.position,
408                    )
409                }),
410                operation_kind:
411                    ast::OperationKind::Subscription,
412                selection_set:
413                    gp_selection_set_to_ast(
414                        &sub.selection_set,
415                        ctx,
416                    ),
417                shorthand: false,
418                span: ctx
419                    .span_from_pos(sub.position),
420                syntax: None,
421                variable_definitions: sub
422                    .variable_definitions
423                    .iter()
424                    .map(|vd| {
425                        gp_variable_def_to_ast(vd, ctx)
426                    })
427                    .collect(),
428            }
429        },
430    }
431}