Coverage Report

Created: 2025-02-21 07:11

/rust/registry/src/index.crates.io-6f17d22bba15001f/async-graphql-7.0.15/src/dynamic/resolve.rs
Line
Count
Source (jump to first uncovered line)
1
use std::{borrow::Cow, pin::Pin};
2
3
use async_graphql_derive::SimpleObject;
4
use async_graphql_parser::{types::Field, Positioned};
5
use futures_util::{future::BoxFuture, Future, FutureExt};
6
use indexmap::IndexMap;
7
8
use crate::{
9
    dynamic::{
10
        field::FieldValueInner, FieldFuture, FieldValue, Object, ObjectAccessor, ResolverContext,
11
        Schema, Type, TypeRef,
12
    },
13
    extensions::ResolveInfo,
14
    parser::types::Selection,
15
    resolver_utils::create_value_object,
16
    Context, ContextSelectionSet, Error, IntrospectionMode, Name, SDLExportOptions, ServerError,
17
    ServerResult, Value,
18
};
19
20
/// Federation service
21
0
#[derive(SimpleObject)]
Unexecuted instantiation: <async_graphql::dynamic::resolve::Service>::sdl::{closure#0}
Unexecuted instantiation: <async_graphql::dynamic::resolve::Service as async_graphql::resolver_utils::container::ContainerType>::resolve_field::{closure#0}::{closure#0}::{closure#0}
Unexecuted instantiation: <async_graphql::dynamic::resolve::Service as async_graphql::resolver_utils::container::ContainerType>::resolve_field::{closure#0}::{closure#1}
Unexecuted instantiation: <async_graphql::dynamic::resolve::Service as async_graphql::base::OutputType>::type_name
Unexecuted instantiation: <async_graphql::dynamic::resolve::Service as async_graphql::base::OutputType>::create_type_info::{closure#0}
Unexecuted instantiation: <async_graphql::dynamic::resolve::Service as async_graphql::base::OutputType>::resolve::{closure#0}
Unexecuted instantiation: <async_graphql::dynamic::resolve::Service as async_graphql::resolver_utils::container::ContainerType>::resolve_field::{closure#0}
Unexecuted instantiation: <async_graphql::dynamic::resolve::Service as async_graphql::resolver_utils::container::ContainerType>::resolve_field::{closure#0}::{closure#0}
Unexecuted instantiation: <async_graphql::dynamic::resolve::Service as async_graphql::base::OutputType>::create_type_info
22
#[graphql(internal, name = "_Service")]
23
struct Service {
24
    sdl: Option<String>,
25
}
26
27
type BoxFieldFuture<'a> = Pin<Box<dyn Future<Output = ServerResult<(Name, Value)>> + 'a + Send>>;
28
29
0
pub(crate) async fn resolve_container(
30
0
    schema: &Schema,
31
0
    object: &Object,
32
0
    ctx: &ContextSelectionSet<'_>,
33
0
    parent_value: &FieldValue<'_>,
34
0
    serial: bool,
35
0
) -> ServerResult<Option<Value>> {
36
0
    let mut fields = Vec::new();
37
0
    collect_fields(&mut fields, schema, object, ctx, parent_value)?;
38
39
0
    let res = if !serial {
40
0
        futures_util::future::try_join_all(fields).await?
41
    } else {
42
0
        let mut results = Vec::with_capacity(fields.len());
43
0
        for field in fields {
44
0
            results.push(field.await?);
45
        }
46
0
        results
47
    };
48
49
0
    Ok(Some(create_value_object(res)))
50
0
}
51
52
0
fn collect_typename_field<'a>(
53
0
    fields: &mut Vec<BoxFieldFuture<'a>>,
54
0
    object: &'a Object,
55
0
    ctx: &ContextSelectionSet<'a>,
56
0
    field: &'a Positioned<Field>,
57
0
) {
58
0
    if matches!(
59
0
        ctx.schema_env.registry.introspection_mode,
60
        IntrospectionMode::Enabled | IntrospectionMode::IntrospectionOnly
61
0
    ) && matches!(
62
0
        ctx.query_env.introspection_mode,
63
        IntrospectionMode::Enabled | IntrospectionMode::IntrospectionOnly,
64
    ) {
65
0
        fields.push(
66
0
            async move {
67
0
                Ok((
68
0
                    field.node.response_key().node.clone(),
69
0
                    Value::from(object.name.as_str()),
70
0
                ))
71
0
            }
72
0
            .boxed(),
73
0
        )
74
    } else {
75
0
        fields
76
0
            .push(async move { Ok((field.node.response_key().node.clone(), Value::Null)) }.boxed())
77
    }
78
0
}
79
80
0
fn collect_schema_field<'a>(
81
0
    fields: &mut Vec<BoxFieldFuture<'a>>,
82
0
    ctx: &ContextSelectionSet<'a>,
83
0
    field: &'a Positioned<Field>,
84
0
) {
85
0
    let ctx = ctx.clone();
86
0
    fields.push(
87
0
        async move {
88
0
            let ctx_field = ctx.with_field(field);
89
0
            let mut ctx_obj = ctx.with_selection_set(&ctx_field.item.node.selection_set);
90
0
            ctx_obj.is_for_introspection = true;
91
0
            let visible_types = ctx.schema_env.registry.find_visible_types(&ctx_field);
92
0
            let value = crate::OutputType::resolve(
93
0
                &crate::model::__Schema::new(&ctx.schema_env.registry, &visible_types),
94
0
                &ctx_obj,
95
0
                ctx_field.item,
96
0
            )
97
0
            .await?;
98
0
            Ok((field.node.response_key().node.clone(), value))
99
0
        }
100
0
        .boxed(),
101
0
    );
102
0
}
103
104
0
fn collect_type_field<'a>(
105
0
    fields: &mut Vec<BoxFieldFuture<'a>>,
106
0
    ctx: &ContextSelectionSet<'a>,
107
0
    field: &'a Positioned<Field>,
108
0
) {
109
0
    let ctx = ctx.clone();
110
0
    fields.push(
111
0
        async move {
112
0
            let ctx_field = ctx.with_field(field);
113
0
            let (_, type_name) = ctx_field.param_value::<String>("name", None)?;
114
0
            let mut ctx_obj = ctx.with_selection_set(&ctx_field.item.node.selection_set);
115
0
            ctx_obj.is_for_introspection = true;
116
0
            let visible_types = ctx.schema_env.registry.find_visible_types(&ctx_field);
117
0
            let value = crate::OutputType::resolve(
118
0
                &ctx.schema_env
119
0
                    .registry
120
0
                    .types
121
0
                    .get(&type_name)
122
0
                    .filter(|_| visible_types.contains(type_name.as_str()))
123
0
                    .map(|ty| {
124
0
                        crate::model::__Type::new_simple(
125
0
                            &ctx.schema_env.registry,
126
0
                            &visible_types,
127
0
                            ty,
128
0
                        )
129
0
                    }),
130
0
                &ctx_obj,
131
0
                ctx_field.item,
132
0
            )
133
0
            .await?;
134
0
            Ok((field.node.response_key().node.clone(), value))
135
0
        }
136
0
        .boxed(),
137
0
    );
138
0
}
139
140
0
fn collect_service_field<'a>(
141
0
    fields: &mut Vec<BoxFieldFuture<'a>>,
142
0
    ctx: &ContextSelectionSet<'a>,
143
0
    field: &'a Positioned<Field>,
144
0
) {
145
0
    let ctx = ctx.clone();
146
0
    fields.push(
147
0
        async move {
148
0
            let ctx_field = ctx.with_field(field);
149
0
            let mut ctx_obj = ctx.with_selection_set(&ctx_field.item.node.selection_set);
150
0
            ctx_obj.is_for_introspection = true;
151
152
0
            let output_type = crate::OutputType::resolve(
153
0
                &Service {
154
0
                    sdl: Some(
155
0
                        ctx.schema_env
156
0
                            .registry
157
0
                            .export_sdl(SDLExportOptions::new().federation().compose_directive()),
158
0
                    ),
159
0
                },
160
0
                &ctx_obj,
161
0
                ctx_field.item,
162
0
            )
163
0
            .await?;
164
165
0
            Ok((field.node.response_key().node.clone(), output_type))
166
0
        }
167
0
        .boxed(),
168
0
    );
169
0
}
170
171
0
fn collect_entities_field<'a>(
172
0
    fields: &mut Vec<BoxFieldFuture<'a>>,
173
0
    schema: &'a Schema,
174
0
    ctx: &ContextSelectionSet<'a>,
175
0
    parent_value: &'a FieldValue,
176
0
    field: &'a Positioned<Field>,
177
0
) {
178
0
    let ctx = ctx.clone();
179
0
    fields.push(
180
0
        async move {
181
0
            let ctx_field = ctx.with_field(field);
182
0
            let entity_resolver = schema.0.entity_resolver.as_ref().ok_or_else(|| {
183
0
                ctx_field.set_error_path(
184
0
                    Error::new("internal: missing entity resolver")
185
0
                        .into_server_error(ctx_field.item.pos),
186
0
                )
187
0
            })?;
188
0
            let entity_type = TypeRef::named_list_nn("_Entity");
189
190
0
            let arguments = ObjectAccessor(Cow::Owned(
191
0
                field
192
0
                    .node
193
0
                    .arguments
194
0
                    .iter()
195
0
                    .map(|(name, value)| {
196
0
                        ctx_field
197
0
                            .resolve_input_value(value.clone())
198
0
                            .map(|value| (name.node.clone(), value))
199
0
                    })
200
0
                    .collect::<ServerResult<IndexMap<Name, Value>>>()?,
201
            ));
202
203
0
            let field_future = (entity_resolver)(ResolverContext {
204
0
                ctx: &ctx_field,
205
0
                args: arguments,
206
0
                parent_value,
207
0
            });
208
209
0
            let field_value = match field_future {
210
0
                FieldFuture::Future(fut) => {
211
0
                    fut.await.map_err(|err| err.into_server_error(field.pos))?
212
                }
213
0
                FieldFuture::Value(value) => value,
214
            };
215
0
            let value = resolve(schema, &ctx_field, &entity_type, field_value.as_ref())
216
0
                .await?
217
0
                .unwrap_or_default();
218
0
            Ok((field.node.response_key().node.clone(), value))
219
0
        }
220
0
        .boxed(),
221
0
    );
222
0
}
223
224
0
fn collect_field<'a>(
225
0
    fields: &mut Vec<BoxFieldFuture<'a>>,
226
0
    schema: &'a Schema,
227
0
    object: &'a Object,
228
0
    ctx: &ContextSelectionSet<'a>,
229
0
    parent_value: &'a FieldValue,
230
0
    field_def: &'a crate::dynamic::Field,
231
0
    field: &'a Positioned<Field>,
232
0
) {
233
0
    let ctx = ctx.clone();
234
0
    fields.push(
235
0
        async move {
236
0
            let ctx_field = ctx.with_field(field);
237
0
            let arguments = ObjectAccessor(Cow::Owned({
238
0
                let mut args = field
239
0
                    .node
240
0
                    .arguments
241
0
                    .iter()
242
0
                    .map(|(name, value)| {
243
0
                        ctx_field
244
0
                            .resolve_input_value(value.clone())
245
0
                            .map(|value| (name.node.clone(), value))
246
0
                    })
247
0
                    .collect::<ServerResult<IndexMap<Name, Value>>>()?;
248
0
                field_def.arguments.iter().for_each(|(name, arg)| {
249
0
                    if let Some(def) = &arg.default_value {
250
0
                        if !args.contains_key(name.as_str()) {
251
0
                            args.insert(Name::new(name), def.clone());
252
0
                        }
253
0
                    }
254
0
                });
255
0
                args
256
0
            }));
257
0
258
0
            let resolve_info = ResolveInfo {
259
0
                path_node: ctx_field.path_node.as_ref().unwrap(),
260
0
                parent_type: &object.name,
261
0
                return_type: &field_def.ty_str,
262
0
                name: &field.node.name.node,
263
0
                alias: field.node.alias.as_ref().map(|alias| &*alias.node),
264
0
                is_for_introspection: ctx_field.is_for_introspection,
265
0
                field: &field.node,
266
0
            };
267
0
            let resolve_fut = async {
268
0
                let field_future = (field_def.resolver_fn)(ResolverContext {
269
0
                    ctx: &ctx_field,
270
0
                    args: arguments,
271
0
                    parent_value,
272
0
                });
273
274
0
                let field_value = match field_future {
275
0
                    FieldFuture::Value(field_value) => field_value,
276
0
                    FieldFuture::Future(future) => future
277
0
                        .await
278
0
                        .map_err(|err| err.into_server_error(field.pos))?,
279
                };
280
281
0
                let value =
282
0
                    resolve(schema, &ctx_field, &field_def.ty, field_value.as_ref()).await?;
283
284
0
                Ok(value)
285
0
            };
286
0
            futures_util::pin_mut!(resolve_fut);
287
288
0
            let res_value = ctx_field
289
0
                .query_env
290
0
                .extensions
291
0
                .resolve(resolve_info, &mut resolve_fut)
292
0
                .await?
293
0
                .unwrap_or_default();
294
0
            Ok((field.node.response_key().node.clone(), res_value))
295
0
        }
296
0
        .boxed(),
297
0
    );
298
0
}
299
300
0
fn collect_fields<'a>(
301
0
    fields: &mut Vec<BoxFieldFuture<'a>>,
302
0
    schema: &'a Schema,
303
0
    object: &'a Object,
304
0
    ctx: &ContextSelectionSet<'a>,
305
0
    parent_value: &'a FieldValue,
306
0
) -> ServerResult<()> {
307
0
    for selection in &ctx.item.node.items {
308
0
        match &selection.node {
309
0
            Selection::Field(field) => {
310
0
                if field.node.name.node == "__typename" {
311
0
                    collect_typename_field(fields, object, ctx, field);
312
0
                    continue;
313
0
                }
314
0
315
0
                if object.name == schema.0.env.registry.query_type
316
0
                    && matches!(
317
0
                        ctx.schema_env.registry.introspection_mode,
318
                        IntrospectionMode::Enabled | IntrospectionMode::IntrospectionOnly
319
                    )
320
0
                    && matches!(
321
0
                        ctx.query_env.introspection_mode,
322
                        IntrospectionMode::Enabled | IntrospectionMode::IntrospectionOnly,
323
                    )
324
                {
325
                    // is query root
326
0
                    if field.node.name.node == "__schema" {
327
0
                        collect_schema_field(fields, ctx, field);
328
0
                        continue;
329
0
                    } else if field.node.name.node == "__type" {
330
0
                        collect_type_field(fields, ctx, field);
331
0
                        continue;
332
0
                    } else if ctx.schema_env.registry.enable_federation
333
0
                        && field.node.name.node == "_service"
334
                    {
335
0
                        collect_service_field(fields, ctx, field);
336
0
                        continue;
337
0
                    } else if ctx.schema_env.registry.enable_federation
338
0
                        && field.node.name.node == "_entities"
339
                    {
340
0
                        collect_entities_field(fields, schema, ctx, parent_value, field);
341
0
                        continue;
342
0
                    }
343
0
                }
344
345
0
                if ctx.schema_env.registry.introspection_mode
346
0
                    == IntrospectionMode::IntrospectionOnly
347
0
                    || ctx.query_env.introspection_mode == IntrospectionMode::IntrospectionOnly
348
                {
349
0
                    fields.push(
350
0
                        async move { Ok((field.node.response_key().node.clone(), Value::Null)) }
351
0
                            .boxed(),
352
0
                    );
353
0
                    continue;
354
0
                }
355
356
0
                if let Some(field_def) = object.fields.get(field.node.name.node.as_str()) {
357
0
                    collect_field(fields, schema, object, ctx, parent_value, field_def, field);
358
0
                }
359
            }
360
0
            selection => {
361
0
                let (type_condition, selection_set) = match selection {
362
0
                    Selection::Field(_) => unreachable!(),
363
0
                    Selection::FragmentSpread(spread) => {
364
0
                        let fragment = ctx.query_env.fragments.get(&spread.node.fragment_name.node);
365
0
                        let fragment = match fragment {
366
0
                            Some(fragment) => fragment,
367
                            None => {
368
0
                                return Err(ServerError::new(
369
0
                                    format!(
370
0
                                        "Unknown fragment \"{}\".",
371
0
                                        spread.node.fragment_name.node
372
0
                                    ),
373
0
                                    Some(spread.pos),
374
0
                                ));
375
                            }
376
                        };
377
0
                        (
378
0
                            Some(&fragment.node.type_condition),
379
0
                            &fragment.node.selection_set,
380
0
                        )
381
                    }
382
0
                    Selection::InlineFragment(fragment) => (
383
0
                        fragment.node.type_condition.as_ref(),
384
0
                        &fragment.node.selection_set,
385
0
                    ),
386
                };
387
388
0
                let type_condition =
389
0
                    type_condition.map(|condition| condition.node.on.node.as_str());
390
0
                let introspection_type_name = &object.name;
391
392
0
                let type_condition_matched = match type_condition {
393
0
                    None => true,
394
0
                    Some(type_condition) if type_condition == introspection_type_name => true,
395
0
                    Some(type_condition) if object.implements.contains(type_condition) => true,
396
0
                    _ => false,
397
                };
398
0
                if type_condition_matched {
399
0
                    collect_fields(
400
0
                        fields,
401
0
                        schema,
402
0
                        object,
403
0
                        &ctx.with_selection_set(selection_set),
404
0
                        parent_value,
405
0
                    )?;
406
0
                }
407
            }
408
        }
409
    }
410
411
0
    Ok(())
412
0
}
413
414
0
pub(crate) fn resolve<'a>(
415
0
    schema: &'a Schema,
416
0
    ctx: &'a Context<'a>,
417
0
    type_ref: &'a TypeRef,
418
0
    value: Option<&'a FieldValue>,
419
0
) -> BoxFuture<'a, ServerResult<Option<Value>>> {
420
0
    async move {
421
0
        match (type_ref, value) {
422
0
            (TypeRef::Named(type_name), Some(value)) => {
423
0
                resolve_value(schema, ctx, &schema.0.types[type_name.as_ref()], value).await
424
            }
425
0
            (TypeRef::Named(_), None) => Ok(None),
426
427
0
            (TypeRef::NonNull(type_ref), Some(value)) => {
428
0
                resolve(schema, ctx, type_ref, Some(value)).await
429
            }
430
0
            (TypeRef::NonNull(_), None) => Err(ctx.set_error_path(
431
0
                Error::new("internal: non-null types require a return value")
432
0
                    .into_server_error(ctx.item.pos),
433
0
            )),
434
435
0
            (TypeRef::List(type_ref), Some(FieldValue(FieldValueInner::List(values)))) => {
436
0
                resolve_list(schema, ctx, type_ref, values).await
437
            }
438
            (
439
0
                TypeRef::List(type_ref),
440
0
                Some(FieldValue(FieldValueInner::Value(Value::List(values)))),
441
0
            ) => {
442
0
                let values = values
443
0
                    .iter()
444
0
                    .cloned()
445
0
                    .map(FieldValue::value)
446
0
                    .collect::<Vec<_>>();
447
0
                resolve_list(schema, ctx, type_ref, &values).await
448
            }
449
0
            (TypeRef::List(_), Some(_)) => Err(ctx.set_error_path(
450
0
                Error::new("internal: expects an array").into_server_error(ctx.item.pos),
451
0
            )),
452
0
            (TypeRef::List(_), None) => Ok(None),
453
        }
454
0
    }
455
0
    .boxed()
456
0
}
457
458
0
async fn resolve_list<'a>(
459
0
    schema: &'a Schema,
460
0
    ctx: &'a Context<'a>,
461
0
    type_ref: &'a TypeRef,
462
0
    values: &[FieldValue<'_>],
463
0
) -> ServerResult<Option<Value>> {
464
0
    let mut futures = Vec::with_capacity(values.len());
465
0
    for (idx, value) in values.iter().enumerate() {
466
0
        let ctx_item = ctx.with_index(idx);
467
0
468
0
        futures.push(async move {
469
0
            let parent_type = format!("[{}]", type_ref);
470
0
            let return_type = type_ref.to_string();
471
0
            let resolve_info = ResolveInfo {
472
0
                path_node: ctx_item.path_node.as_ref().unwrap(),
473
0
                parent_type: &parent_type,
474
0
                return_type: &return_type,
475
0
                name: ctx.item.node.name.node.as_str(),
476
0
                alias: ctx
477
0
                    .item
478
0
                    .node
479
0
                    .alias
480
0
                    .as_ref()
481
0
                    .map(|alias| alias.node.as_str()),
482
0
                is_for_introspection: ctx_item.is_for_introspection,
483
0
                field: &ctx_item.item.node,
484
0
            };
485
0
486
0
            let resolve_fut = async { resolve(schema, &ctx_item, type_ref, Some(value)).await };
487
0
            futures_util::pin_mut!(resolve_fut);
488
489
0
            let res_value = ctx_item
490
0
                .query_env
491
0
                .extensions
492
0
                .resolve(resolve_info, &mut resolve_fut)
493
0
                .await?;
494
0
            Ok::<_, ServerError>(res_value.unwrap_or_default())
495
0
        });
496
0
    }
497
0
    let values = futures_util::future::try_join_all(futures).await?;
498
0
    Ok(Some(Value::List(values)))
499
0
}
500
501
0
async fn resolve_value(
502
0
    schema: &Schema,
503
0
    ctx: &Context<'_>,
504
0
    field_type: &Type,
505
0
    value: &FieldValue<'_>,
506
0
) -> ServerResult<Option<Value>> {
507
0
    match (field_type, &value.0) {
508
0
        (Type::Scalar(scalar), FieldValueInner::Value(value)) if scalar.validate(value) => {
509
0
            Ok(Some(value.clone()))
510
        }
511
0
        (Type::Scalar(scalar), _) => Err(ctx.set_error_path(
512
0
            Error::new(format!(
513
0
                "internal: invalid value for scalar \"{}\", expected \"FieldValue::Value\"",
514
0
                scalar.name
515
0
            ))
516
0
            .into_server_error(ctx.item.pos),
517
0
        )),
518
519
0
        (Type::Object(object), _) => {
520
0
            resolve_container(
521
0
                schema,
522
0
                object,
523
0
                &ctx.with_selection_set(&ctx.item.node.selection_set),
524
0
                value,
525
0
                true,
526
0
            )
527
0
            .await
528
        }
529
530
0
        (Type::InputObject(obj), _) => Err(ctx.set_error_path(
531
0
            Error::new(format!(
532
0
                "internal: cannot use input object \"{}\" as output value",
533
0
                obj.name
534
0
            ))
535
0
            .into_server_error(ctx.item.pos),
536
0
        )),
537
538
0
        (Type::Enum(e), FieldValueInner::Value(Value::Enum(name))) => {
539
0
            if !e.enum_values.contains_key(name.as_str()) {
540
0
                return Err(ctx.set_error_path(
541
0
                    Error::new(format!("internal: invalid item for enum \"{}\"", e.name))
542
0
                        .into_server_error(ctx.item.pos),
543
0
                ));
544
0
            }
545
0
            Ok(Some(Value::Enum(name.clone())))
546
        }
547
0
        (Type::Enum(e), FieldValueInner::Value(Value::String(name))) => {
548
0
            if !e.enum_values.contains_key(name) {
549
0
                return Err(ctx.set_error_path(
550
0
                    Error::new(format!("internal: invalid item for enum \"{}\"", e.name))
551
0
                        .into_server_error(ctx.item.pos),
552
0
                ));
553
0
            }
554
0
            Ok(Some(Value::Enum(Name::new(name))))
555
        }
556
0
        (Type::Enum(e), _) => Err(ctx.set_error_path(
557
0
            Error::new(format!("internal: invalid item for enum \"{}\"", e.name))
558
0
                .into_server_error(ctx.item.pos),
559
0
        )),
560
561
0
        (Type::Interface(interface), FieldValueInner::WithType { value, ty }) => {
562
0
            let is_contains_obj = schema
563
0
                .0
564
0
                .env
565
0
                .registry
566
0
                .types
567
0
                .get(&interface.name)
568
0
                .and_then(|meta_type| {
569
0
                    meta_type
570
0
                        .possible_types()
571
0
                        .map(|possible_types| possible_types.contains(ty.as_ref()))
572
0
                })
573
0
                .unwrap_or_default();
574
0
            if !is_contains_obj {
575
0
                return Err(ctx.set_error_path(
576
0
                    Error::new(format!(
577
0
                        "internal: object \"{}\" does not implement interface \"{}\"",
578
0
                        ty, interface.name,
579
0
                    ))
580
0
                    .into_server_error(ctx.item.pos),
581
0
                ));
582
0
            }
583
584
0
            let object_type = schema
585
0
                .0
586
0
                .types
587
0
                .get(ty.as_ref())
588
0
                .ok_or_else(|| {
589
0
                    ctx.set_error_path(
590
0
                        Error::new(format!("internal: object \"{}\" does not registered", ty))
591
0
                            .into_server_error(ctx.item.pos),
592
0
                    )
593
0
                })?
594
0
                .as_object()
595
0
                .ok_or_else(|| {
596
0
                    ctx.set_error_path(
597
0
                        Error::new(format!("internal: type \"{}\" is not object", ty))
598
0
                            .into_server_error(ctx.item.pos),
599
0
                    )
600
0
                })?;
601
602
0
            resolve_container(
603
0
                schema,
604
0
                object_type,
605
0
                &ctx.with_selection_set(&ctx.item.node.selection_set),
606
0
                value,
607
0
                true,
608
0
            )
609
0
            .await
610
        }
611
0
        (Type::Interface(interface), _) => Err(ctx.set_error_path(
612
0
            Error::new(format!(
613
0
                "internal: invalid value for interface \"{}\", expected \"FieldValue::WithType\"",
614
0
                interface.name
615
0
            ))
616
0
            .into_server_error(ctx.item.pos),
617
0
        )),
618
619
0
        (Type::Union(union), FieldValueInner::WithType { value, ty }) => {
620
0
            if !union.possible_types.contains(ty.as_ref()) {
621
0
                return Err(ctx.set_error_path(
622
0
                    Error::new(format!(
623
0
                        "internal: union \"{}\" does not contain object \"{}\"",
624
0
                        union.name, ty,
625
0
                    ))
626
0
                    .into_server_error(ctx.item.pos),
627
0
                ));
628
0
            }
629
630
0
            let object_type = schema
631
0
                .0
632
0
                .types
633
0
                .get(ty.as_ref())
634
0
                .ok_or_else(|| {
635
0
                    ctx.set_error_path(
636
0
                        Error::new(format!("internal: object \"{}\" does not registered", ty))
637
0
                            .into_server_error(ctx.item.pos),
638
0
                    )
639
0
                })?
640
0
                .as_object()
641
0
                .ok_or_else(|| {
642
0
                    ctx.set_error_path(
643
0
                        Error::new(format!("internal: type \"{}\" is not object", ty))
644
0
                            .into_server_error(ctx.item.pos),
645
0
                    )
646
0
                })?;
647
648
0
            resolve_container(
649
0
                schema,
650
0
                object_type,
651
0
                &ctx.with_selection_set(&ctx.item.node.selection_set),
652
0
                value,
653
0
                true,
654
0
            )
655
0
            .await
656
        }
657
0
        (Type::Union(union), _) => Err(ctx.set_error_path(
658
0
            Error::new(format!(
659
0
                "internal: invalid value for union \"{}\", expected \"FieldValue::WithType\"",
660
0
                union.name
661
0
            ))
662
0
            .into_server_error(ctx.item.pos),
663
0
        )),
664
0
        (Type::Subscription(subscription), _) => Err(ctx.set_error_path(
665
0
            Error::new(format!(
666
0
                "internal: cannot use subscription \"{}\" as output value",
667
0
                subscription.name
668
0
            ))
669
0
            .into_server_error(ctx.item.pos),
670
0
        )),
671
0
        (Type::Upload, _) => Err(ctx.set_error_path(
672
0
            Error::new("internal: cannot use upload as output value")
673
0
                .into_server_error(ctx.item.pos),
674
0
        )),
675
    }
676
0
}