1use juniper::IntoFieldError;
4use std::{borrow::Cow, fmt};
5
6use crate::{
7 ast::{FromInputValue, InputValue, Type},
8 parser::{ParseError, ScalarToken},
9 schema::model::SchemaType,
10 types::base::TypeKind,
11 value::{DefaultScalarValue, ParseScalarValue},
12 FieldError,
13};
14
15#[derive(Clone, Debug, Eq, Hash, PartialEq)]
17pub enum DeprecationStatus {
18 Current,
20 Deprecated(Option<String>),
22}
23
24impl DeprecationStatus {
25 pub fn is_deprecated(&self) -> bool {
27 match self {
28 DeprecationStatus::Current => false,
29 DeprecationStatus::Deprecated(_) => true,
30 }
31 }
32
33 pub fn reason(&self) -> Option<&str> {
35 match self {
36 DeprecationStatus::Current => None,
37 DeprecationStatus::Deprecated(rsn) => rsn.as_deref(),
38 }
39 }
40}
41
42pub struct ScalarMeta<'a, S> {
44 #[doc(hidden)]
45 pub name: Cow<'a, str>,
46 #[doc(hidden)]
47 pub description: Option<String>,
48 #[doc(hidden)]
49 pub specified_by_url: Option<Cow<'a, str>>,
50 pub(crate) try_parse_fn: InputValueParseFn<S>,
51 pub(crate) parse_fn: ScalarTokenParseFn<S>,
52}
53
54pub type InputValueParseFn<S> = for<'b> fn(&'b InputValue<S>) -> Result<(), FieldError<S>>;
56
57pub type ScalarTokenParseFn<S> = for<'b> fn(ScalarToken<'b>) -> Result<S, ParseError>;
59
60#[derive(Debug)]
62pub struct ListMeta<'a> {
63 #[doc(hidden)]
64 pub of_type: Type<'a>,
65
66 #[doc(hidden)]
67 pub expected_size: Option<usize>,
68}
69
70#[derive(Debug)]
72pub struct NullableMeta<'a> {
73 #[doc(hidden)]
74 pub of_type: Type<'a>,
75}
76
77#[derive(Debug)]
79pub struct ObjectMeta<'a, S> {
80 #[doc(hidden)]
81 pub name: Cow<'a, str>,
82 #[doc(hidden)]
83 pub description: Option<String>,
84 #[doc(hidden)]
85 pub fields: Vec<Field<'a, S>>,
86 #[doc(hidden)]
87 pub interface_names: Vec<String>,
88}
89
90pub struct EnumMeta<'a, S> {
92 #[doc(hidden)]
93 pub name: Cow<'a, str>,
94 #[doc(hidden)]
95 pub description: Option<String>,
96 #[doc(hidden)]
97 pub values: Vec<EnumValue>,
98 pub(crate) try_parse_fn: InputValueParseFn<S>,
99}
100
101#[derive(Debug)]
103pub struct InterfaceMeta<'a, S> {
104 #[doc(hidden)]
105 pub name: Cow<'a, str>,
106 #[doc(hidden)]
107 pub description: Option<String>,
108 #[doc(hidden)]
109 pub fields: Vec<Field<'a, S>>,
110 #[doc(hidden)]
111 pub interface_names: Vec<String>,
112}
113
114#[derive(Debug)]
116pub struct UnionMeta<'a> {
117 #[doc(hidden)]
118 pub name: Cow<'a, str>,
119 #[doc(hidden)]
120 pub description: Option<String>,
121 #[doc(hidden)]
122 pub of_type_names: Vec<String>,
123}
124
125pub struct InputObjectMeta<'a, S> {
127 #[doc(hidden)]
128 pub name: Cow<'a, str>,
129 #[doc(hidden)]
130 pub description: Option<String>,
131 #[doc(hidden)]
132 pub input_fields: Vec<Argument<'a, S>>,
133 pub(crate) try_parse_fn: InputValueParseFn<S>,
134}
135
136#[derive(Debug)]
141pub struct PlaceholderMeta<'a> {
142 #[doc(hidden)]
143 pub of_type: Type<'a>,
144}
145
146#[derive(Debug)]
148pub enum MetaType<'a, S = DefaultScalarValue> {
149 #[doc(hidden)]
150 Scalar(ScalarMeta<'a, S>),
151 #[doc(hidden)]
152 List(ListMeta<'a>),
153 #[doc(hidden)]
154 Nullable(NullableMeta<'a>),
155 #[doc(hidden)]
156 Object(ObjectMeta<'a, S>),
157 #[doc(hidden)]
158 Enum(EnumMeta<'a, S>),
159 #[doc(hidden)]
160 Interface(InterfaceMeta<'a, S>),
161 #[doc(hidden)]
162 Union(UnionMeta<'a>),
163 #[doc(hidden)]
164 InputObject(InputObjectMeta<'a, S>),
165 #[doc(hidden)]
166 Placeholder(PlaceholderMeta<'a>),
167}
168
169#[derive(Debug, Clone)]
171pub struct Field<'a, S> {
172 #[doc(hidden)]
173 pub name: smartstring::alias::String,
174 #[doc(hidden)]
175 pub description: Option<String>,
176 #[doc(hidden)]
177 pub arguments: Option<Vec<Argument<'a, S>>>,
178 #[doc(hidden)]
179 pub field_type: Type<'a>,
180 #[doc(hidden)]
181 pub deprecation_status: DeprecationStatus,
182}
183
184impl<'a, S> Field<'a, S> {
185 pub fn is_builtin(&self) -> bool {
187 self.name.starts_with("__")
189 }
190}
191
192#[derive(Debug, Clone)]
194pub struct Argument<'a, S> {
195 #[doc(hidden)]
196 pub name: String,
197 #[doc(hidden)]
198 pub description: Option<String>,
199 #[doc(hidden)]
200 pub arg_type: Type<'a>,
201 #[doc(hidden)]
202 pub default_value: Option<InputValue<S>>,
203}
204
205impl<'a, S> Argument<'a, S> {
206 pub fn is_builtin(&self) -> bool {
208 self.name.starts_with("__")
210 }
211}
212
213#[derive(Debug, Clone)]
215pub struct EnumValue {
216 pub name: String,
220 pub description: Option<String>,
225 pub deprecation_status: DeprecationStatus,
227}
228
229impl<'a, S> MetaType<'a, S> {
230 pub fn name(&self) -> Option<&str> {
234 match *self {
235 MetaType::Scalar(ScalarMeta { ref name, .. })
236 | MetaType::Object(ObjectMeta { ref name, .. })
237 | MetaType::Enum(EnumMeta { ref name, .. })
238 | MetaType::Interface(InterfaceMeta { ref name, .. })
239 | MetaType::Union(UnionMeta { ref name, .. })
240 | MetaType::InputObject(InputObjectMeta { ref name, .. }) => Some(name),
241 _ => None,
242 }
243 }
244
245 pub fn description(&self) -> Option<&str> {
249 match self {
250 MetaType::Scalar(ScalarMeta { description, .. })
251 | MetaType::Object(ObjectMeta { description, .. })
252 | MetaType::Enum(EnumMeta { description, .. })
253 | MetaType::Interface(InterfaceMeta { description, .. })
254 | MetaType::Union(UnionMeta { description, .. })
255 | MetaType::InputObject(InputObjectMeta { description, .. }) => description.as_deref(),
256 _ => None,
257 }
258 }
259
260 pub fn specified_by_url(&self) -> Option<&str> {
266 match self {
267 Self::Scalar(ScalarMeta {
268 specified_by_url, ..
269 }) => specified_by_url.as_deref(),
270 _ => None,
271 }
272 }
273
274 pub fn type_kind(&self) -> TypeKind {
280 match *self {
281 MetaType::Scalar(_) => TypeKind::Scalar,
282 MetaType::List(_) => TypeKind::List,
283 MetaType::Nullable(_) => panic!("Can't take type_kind of nullable meta type"),
284 MetaType::Object(_) => TypeKind::Object,
285 MetaType::Enum(_) => TypeKind::Enum,
286 MetaType::Interface(_) => TypeKind::Interface,
287 MetaType::Union(_) => TypeKind::Union,
288 MetaType::InputObject(_) => TypeKind::InputObject,
289 MetaType::Placeholder(_) => panic!("Can't take type_kind of placeholder meta type"),
290 }
291 }
292
293 pub fn field_by_name(&self, name: &str) -> Option<&Field<S>> {
297 match *self {
298 MetaType::Object(ObjectMeta { ref fields, .. })
299 | MetaType::Interface(InterfaceMeta { ref fields, .. }) => {
300 fields.iter().find(|f| f.name == name)
301 }
302 _ => None,
303 }
304 }
305
306 pub fn input_field_by_name(&self, name: &str) -> Option<&Argument<S>> {
310 match *self {
311 MetaType::InputObject(InputObjectMeta {
312 ref input_fields, ..
313 }) => input_fields.iter().find(|f| f.name == name),
314 _ => None,
315 }
316 }
317
318 pub fn as_type(&self) -> Type<'a> {
320 match *self {
321 MetaType::Scalar(ScalarMeta { ref name, .. })
322 | MetaType::Object(ObjectMeta { ref name, .. })
323 | MetaType::Enum(EnumMeta { ref name, .. })
324 | MetaType::Interface(InterfaceMeta { ref name, .. })
325 | MetaType::Union(UnionMeta { ref name, .. })
326 | MetaType::InputObject(InputObjectMeta { ref name, .. }) => {
327 Type::NonNullNamed(name.clone())
328 }
329 MetaType::List(ListMeta {
330 ref of_type,
331 expected_size,
332 }) => Type::NonNullList(Box::new(of_type.clone()), expected_size),
333 MetaType::Nullable(NullableMeta { ref of_type }) => match *of_type {
334 Type::NonNullNamed(ref inner) => Type::Named(inner.clone()),
335 Type::NonNullList(ref inner, expected_size) => {
336 Type::List(inner.clone(), expected_size)
337 }
338 ref t => t.clone(),
339 },
340 MetaType::Placeholder(PlaceholderMeta { ref of_type }) => of_type.clone(),
341 }
342 }
343
344 pub fn input_value_parse_fn(&self) -> Option<InputValueParseFn<S>> {
351 match *self {
352 MetaType::Scalar(ScalarMeta {
353 ref try_parse_fn, ..
354 })
355 | MetaType::Enum(EnumMeta {
356 ref try_parse_fn, ..
357 })
358 | MetaType::InputObject(InputObjectMeta {
359 ref try_parse_fn, ..
360 }) => Some(*try_parse_fn),
361 _ => None,
362 }
363 }
364
365 pub fn is_composite(&self) -> bool {
369 matches!(
370 *self,
371 MetaType::Object(_) | MetaType::Interface(_) | MetaType::Union(_)
372 )
373 }
374
375 pub fn is_leaf(&self) -> bool {
379 matches!(*self, MetaType::Enum(_) | MetaType::Scalar(_))
380 }
381
382 pub fn is_abstract(&self) -> bool {
386 matches!(*self, MetaType::Interface(_) | MetaType::Union(_))
387 }
388
389 pub fn is_input(&self) -> bool {
393 matches!(
394 *self,
395 MetaType::Scalar(_) | MetaType::Enum(_) | MetaType::InputObject(_)
396 )
397 }
398
399 pub fn is_builtin(&self) -> bool {
401 if let Some(name) = self.name() {
402 {
404 name.starts_with("__") ||
405 name == "Boolean" || name == "String" || name == "Int" || name == "Float" || name == "ID" ||
407 name == "_EmptyMutation" || name == "_EmptySubscription"
409 }
410 } else {
411 false
412 }
413 }
414
415 pub(crate) fn fields<'b>(&self, schema: &'b SchemaType<S>) -> Option<Vec<&'b Field<'b, S>>> {
416 schema
417 .lookup_type(&self.as_type())
418 .and_then(|tpe| match *tpe {
419 MetaType::Interface(ref i) => Some(i.fields.iter().collect()),
420 MetaType::Object(ref o) => Some(o.fields.iter().collect()),
421 MetaType::Union(ref u) => Some(
422 u.of_type_names
423 .iter()
424 .filter_map(|n| schema.concrete_type_by_name(n))
425 .filter_map(|t| t.fields(schema))
426 .flatten()
427 .collect(),
428 ),
429 _ => None,
430 })
431 }
432}
433
434impl<'a, S> ScalarMeta<'a, S> {
435 pub fn new<T>(name: Cow<'a, str>) -> Self
437 where
438 T: FromInputValue<S> + ParseScalarValue<S>,
439 T::Error: IntoFieldError<S>,
440 {
441 Self {
442 name,
443 description: None,
444 specified_by_url: None,
445 try_parse_fn: try_parse_fn::<S, T>,
446 parse_fn: <T as ParseScalarValue<S>>::from_str,
447 }
448 }
449
450 #[must_use]
454 pub fn description(mut self, description: &str) -> Self {
455 self.description = Some(description.into());
456 self
457 }
458
459 #[must_use]
465 pub fn specified_by_url(mut self, url: impl Into<Cow<'a, str>>) -> Self {
466 self.specified_by_url = Some(url.into());
467 self
468 }
469
470 pub fn into_meta(self) -> MetaType<'a, S> {
472 MetaType::Scalar(self)
473 }
474}
475
476impl<'a> ListMeta<'a> {
477 pub fn new(of_type: Type<'a>, expected_size: Option<usize>) -> Self {
482 Self {
483 of_type,
484 expected_size,
485 }
486 }
487
488 pub fn into_meta<S>(self) -> MetaType<'a, S> {
490 MetaType::List(self)
491 }
492}
493
494impl<'a> NullableMeta<'a> {
495 pub fn new(of_type: Type<'a>) -> Self {
497 Self { of_type }
498 }
499
500 pub fn into_meta<S>(self) -> MetaType<'a, S> {
502 MetaType::Nullable(self)
503 }
504}
505
506impl<'a, S> ObjectMeta<'a, S> {
507 pub fn new(name: Cow<'a, str>, fields: &[Field<'a, S>]) -> Self
509 where
510 S: Clone,
511 {
512 Self {
513 name,
514 description: None,
515 fields: fields.to_vec(),
516 interface_names: vec![],
517 }
518 }
519
520 #[must_use]
524 pub fn description(mut self, description: &str) -> Self {
525 self.description = Some(description.into());
526 self
527 }
528
529 #[must_use]
533 pub fn interfaces(mut self, interfaces: &[Type<'a>]) -> Self {
534 self.interface_names = interfaces
535 .iter()
536 .map(|t| t.innermost_name().into())
537 .collect();
538 self
539 }
540
541 pub fn into_meta(self) -> MetaType<'a, S> {
543 MetaType::Object(self)
544 }
545}
546
547impl<'a, S> EnumMeta<'a, S> {
548 pub fn new<T>(name: Cow<'a, str>, values: &[EnumValue]) -> Self
551 where
552 T: FromInputValue<S>,
553 T::Error: IntoFieldError<S>,
554 {
555 Self {
556 name,
557 description: None,
558 values: values.to_owned(),
559 try_parse_fn: try_parse_fn::<S, T>,
560 }
561 }
562
563 #[must_use]
567 pub fn description(mut self, description: &str) -> Self {
568 self.description = Some(description.into());
569 self
570 }
571
572 pub fn into_meta(self) -> MetaType<'a, S> {
574 MetaType::Enum(self)
575 }
576}
577
578impl<'a, S> InterfaceMeta<'a, S> {
579 pub fn new(name: Cow<'a, str>, fields: &[Field<'a, S>]) -> Self
582 where
583 S: Clone,
584 {
585 Self {
586 name,
587 description: None,
588 fields: fields.to_vec(),
589 interface_names: Vec::new(),
590 }
591 }
592
593 #[must_use]
597 pub fn description(mut self, description: &str) -> Self {
598 self.description = Some(description.into());
599 self
600 }
601
602 #[must_use]
606 pub fn interfaces(mut self, interfaces: &[Type<'a>]) -> Self {
607 self.interface_names = interfaces
608 .iter()
609 .map(|t| t.innermost_name().into())
610 .collect();
611 self
612 }
613
614 pub fn into_meta(self) -> MetaType<'a, S> {
616 MetaType::Interface(self)
617 }
618}
619
620impl<'a> UnionMeta<'a> {
621 pub fn new(name: Cow<'a, str>, of_types: &[Type]) -> Self {
624 Self {
625 name,
626 description: None,
627 of_type_names: of_types.iter().map(|t| t.innermost_name().into()).collect(),
628 }
629 }
630
631 #[must_use]
635 pub fn description(mut self, description: &str) -> Self {
636 self.description = Some(description.into());
637 self
638 }
639
640 pub fn into_meta<S>(self) -> MetaType<'a, S> {
642 MetaType::Union(self)
643 }
644}
645
646impl<'a, S> InputObjectMeta<'a, S> {
647 pub fn new<T>(name: Cow<'a, str>, input_fields: &[Argument<'a, S>]) -> Self
650 where
651 T: FromInputValue<S>,
652 T::Error: IntoFieldError<S>,
653 S: Clone,
654 {
655 Self {
656 name,
657 description: None,
658 input_fields: input_fields.to_vec(),
659 try_parse_fn: try_parse_fn::<S, T>,
660 }
661 }
662
663 #[must_use]
667 pub fn description(mut self, description: &str) -> Self {
668 self.description = Some(description.into());
669 self
670 }
671
672 pub fn into_meta(self) -> MetaType<'a, S> {
674 MetaType::InputObject(self)
675 }
676}
677
678impl<'a, S> Field<'a, S> {
679 #[must_use]
683 pub fn description(mut self, description: &str) -> Self {
684 self.description = Some(description.into());
685 self
686 }
687
688 #[must_use]
692 pub fn argument(mut self, argument: Argument<'a, S>) -> Self {
693 match self.arguments {
694 None => {
695 self.arguments = Some(vec![argument]);
696 }
697 Some(ref mut args) => {
698 args.push(argument);
699 }
700 };
701 self
702 }
703
704 #[must_use]
708 pub fn deprecated(mut self, reason: Option<&str>) -> Self {
709 self.deprecation_status = DeprecationStatus::Deprecated(reason.map(Into::into));
710 self
711 }
712}
713
714impl<'a, S> Argument<'a, S> {
715 pub fn new(name: &str, arg_type: Type<'a>) -> Self {
717 Self {
718 name: name.into(),
719 description: None,
720 arg_type,
721 default_value: None,
722 }
723 }
724
725 #[must_use]
729 pub fn description(mut self, description: &str) -> Self {
730 self.description = Some(description.into());
731 self
732 }
733
734 #[must_use]
738 pub fn default_value(mut self, val: InputValue<S>) -> Self {
739 self.default_value = Some(val);
740 self
741 }
742}
743
744impl EnumValue {
745 pub fn new(name: &str) -> Self {
747 Self {
748 name: name.into(),
749 description: None,
750 deprecation_status: DeprecationStatus::Current,
751 }
752 }
753
754 #[must_use]
758 pub fn description(mut self, description: &str) -> Self {
759 self.description = Some(description.into());
760 self
761 }
762
763 #[must_use]
767 pub fn deprecated(mut self, reason: Option<&str>) -> Self {
768 self.deprecation_status = DeprecationStatus::Deprecated(reason.map(Into::into));
769 self
770 }
771}
772
773impl<'a, S: fmt::Debug> fmt::Debug for ScalarMeta<'a, S> {
774 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
775 fmt.debug_struct("ScalarMeta")
776 .field("name", &self.name)
777 .field("description", &self.description)
778 .finish()
779 }
780}
781
782impl<'a, S: fmt::Debug> fmt::Debug for EnumMeta<'a, S> {
783 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
784 fmt.debug_struct("EnumMeta")
785 .field("name", &self.name)
786 .field("description", &self.description)
787 .field("values", &self.values)
788 .finish()
789 }
790}
791
792impl<'a, S: fmt::Debug> fmt::Debug for InputObjectMeta<'a, S> {
793 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
794 fmt.debug_struct("InputObjectMeta")
795 .field("name", &self.name)
796 .field("description", &self.description)
797 .field("input_fields", &self.input_fields)
798 .finish()
799 }
800}
801
802fn try_parse_fn<S, T>(v: &InputValue<S>) -> Result<(), FieldError<S>>
803where
804 T: FromInputValue<S>,
805 T::Error: IntoFieldError<S>,
806{
807 T::from_input_value(v)
808 .map(drop)
809 .map_err(T::Error::into_field_error)
810}