1use std::borrow::ToOwned;
4
5use arcstr::ArcStr;
6use derive_more::with_trait::Debug;
7
8use crate::{
9 FieldError, IntoFieldError,
10 ast::{FromInputValue, InputValue, Type},
11 parser::{ParseError, ScalarToken},
12 schema::model::SchemaType,
13 types::base::TypeKind,
14 value::{DefaultScalarValue, ParseScalarValue},
15};
16
17#[derive(Clone, Debug, Eq, Hash, PartialEq)]
19pub enum DeprecationStatus {
20 Current,
22
23 Deprecated(Option<ArcStr>),
25}
26
27impl DeprecationStatus {
28 pub fn is_deprecated(&self) -> bool {
30 match self {
31 Self::Current => false,
32 Self::Deprecated(_) => true,
33 }
34 }
35
36 pub fn reason(&self) -> Option<&ArcStr> {
38 match self {
39 Self::Current => None,
40 Self::Deprecated(rsn) => rsn.as_ref(),
41 }
42 }
43}
44
45#[derive(Debug)]
47pub struct ScalarMeta<S> {
48 #[doc(hidden)]
49 pub name: ArcStr,
50 #[doc(hidden)]
51 pub description: Option<ArcStr>,
52 #[doc(hidden)]
53 pub specified_by_url: Option<ArcStr>,
54 #[debug(ignore)]
55 pub(crate) try_parse_fn: InputValueParseFn<S>,
56 #[debug(ignore)]
57 pub(crate) parse_fn: ScalarTokenParseFn<S>,
58}
59
60impl<S> ScalarMeta<S> {
61 pub fn new<T>(name: impl Into<ArcStr>) -> Self
63 where
64 T: FromInputValue<S> + ParseScalarValue<S>,
65 T::Error: IntoFieldError<S>,
66 {
67 Self {
68 name: name.into(),
69 description: None,
70 specified_by_url: None,
71 try_parse_fn: try_parse_fn::<S, T>,
72 parse_fn: <T as ParseScalarValue<S>>::from_str,
73 }
74 }
75
76 #[must_use]
80 pub fn description(mut self, description: impl Into<ArcStr>) -> Self {
81 self.description = Some(description.into());
82 self
83 }
84
85 #[must_use]
91 pub fn specified_by_url(mut self, url: impl Into<ArcStr>) -> Self {
92 self.specified_by_url = Some(url.into());
93 self
94 }
95
96 pub fn into_meta(self) -> MetaType<S> {
98 MetaType::Scalar(self)
99 }
100}
101
102pub type InputValueParseFn<S> = for<'b> fn(&'b InputValue<S>) -> Result<(), FieldError<S>>;
104
105pub type ScalarTokenParseFn<S> = for<'b> fn(ScalarToken<'b>) -> Result<S, ParseError>;
107
108#[derive(Debug)]
110pub struct ListMeta {
111 #[doc(hidden)]
112 pub of_type: Type,
113
114 #[doc(hidden)]
115 pub expected_size: Option<usize>,
116}
117
118impl ListMeta {
119 pub fn new(of_type: Type, expected_size: Option<usize>) -> Self {
124 Self {
125 of_type,
126 expected_size,
127 }
128 }
129
130 pub fn into_meta<S>(self) -> MetaType<S> {
132 MetaType::List(self)
133 }
134}
135
136#[derive(Debug)]
138pub struct NullableMeta {
139 #[doc(hidden)]
140 pub of_type: Type,
141}
142
143impl NullableMeta {
144 pub fn new(of_type: Type) -> Self {
146 Self { of_type }
147 }
148
149 pub fn into_meta<S>(self) -> MetaType<S> {
151 MetaType::Nullable(self)
152 }
153}
154
155#[derive(Debug)]
157pub struct ObjectMeta<S> {
158 #[doc(hidden)]
159 pub name: ArcStr,
160 #[doc(hidden)]
161 pub description: Option<ArcStr>,
162 #[doc(hidden)]
163 pub fields: Vec<Field<S>>,
164 #[doc(hidden)]
165 pub interface_names: Vec<ArcStr>,
166}
167
168impl<S> ObjectMeta<S> {
169 pub fn new(name: impl Into<ArcStr>, fields: &[Field<S>]) -> Self
171 where
172 S: Clone,
173 {
174 Self {
175 name: name.into(),
176 description: None,
177 fields: fields.to_vec(),
178 interface_names: vec![],
179 }
180 }
181
182 #[must_use]
186 pub fn description(mut self, description: impl Into<ArcStr>) -> Self {
187 self.description = Some(description.into());
188 self
189 }
190
191 #[must_use]
195 pub fn interfaces(mut self, interfaces: &[Type]) -> Self {
196 self.interface_names = interfaces
197 .iter()
198 .map(|t| t.innermost_name().into())
199 .collect();
200 self
201 }
202
203 pub fn into_meta(self) -> MetaType<S> {
205 MetaType::Object(self)
206 }
207}
208
209#[derive(Debug)]
211pub struct EnumMeta<S> {
212 #[doc(hidden)]
213 pub name: ArcStr,
214 #[doc(hidden)]
215 pub description: Option<ArcStr>,
216 #[doc(hidden)]
217 pub values: Vec<EnumValue>,
218 #[debug(ignore)]
219 pub(crate) try_parse_fn: InputValueParseFn<S>,
220}
221
222impl<S> EnumMeta<S> {
223 pub fn new<T>(name: impl Into<ArcStr>, values: &[EnumValue]) -> Self
225 where
226 T: FromInputValue<S>,
227 T::Error: IntoFieldError<S>,
228 {
229 Self {
230 name: name.into(),
231 description: None,
232 values: values.to_owned(),
233 try_parse_fn: try_parse_fn::<S, T>,
234 }
235 }
236
237 #[must_use]
241 pub fn description(mut self, description: impl Into<ArcStr>) -> Self {
242 self.description = Some(description.into());
243 self
244 }
245
246 pub fn into_meta(self) -> MetaType<S> {
248 MetaType::Enum(self)
249 }
250}
251
252#[derive(Debug)]
254pub struct InterfaceMeta<S> {
255 #[doc(hidden)]
256 pub name: ArcStr,
257 #[doc(hidden)]
258 pub description: Option<ArcStr>,
259 #[doc(hidden)]
260 pub fields: Vec<Field<S>>,
261 #[doc(hidden)]
262 pub interface_names: Vec<ArcStr>,
263}
264
265impl<S> InterfaceMeta<S> {
266 pub fn new(name: impl Into<ArcStr>, fields: &[Field<S>]) -> Self
268 where
269 S: Clone,
270 {
271 Self {
272 name: name.into(),
273 description: None,
274 fields: fields.to_vec(),
275 interface_names: Vec::new(),
276 }
277 }
278
279 #[must_use]
283 pub fn description(mut self, description: impl Into<ArcStr>) -> Self {
284 self.description = Some(description.into());
285 self
286 }
287
288 #[must_use]
292 pub fn interfaces(mut self, interfaces: &[Type]) -> Self {
293 self.interface_names = interfaces
294 .iter()
295 .map(|t| t.innermost_name().into())
296 .collect();
297 self
298 }
299
300 pub fn into_meta(self) -> MetaType<S> {
302 MetaType::Interface(self)
303 }
304}
305
306#[derive(Debug)]
308pub struct UnionMeta {
309 #[doc(hidden)]
310 pub name: ArcStr,
311 #[doc(hidden)]
312 pub description: Option<ArcStr>,
313 #[doc(hidden)]
314 pub of_type_names: Vec<ArcStr>,
315}
316
317impl UnionMeta {
318 pub fn new(name: impl Into<ArcStr>, of_types: &[Type]) -> Self {
320 Self {
321 name: name.into(),
322 description: None,
323 of_type_names: of_types.iter().map(|t| t.innermost_name().into()).collect(),
324 }
325 }
326
327 #[must_use]
331 pub fn description(mut self, description: impl Into<ArcStr>) -> Self {
332 self.description = Some(description.into());
333 self
334 }
335
336 pub fn into_meta<S>(self) -> MetaType<S> {
338 MetaType::Union(self)
339 }
340}
341
342#[derive(Debug)]
344pub struct InputObjectMeta<S> {
345 #[doc(hidden)]
346 pub name: ArcStr,
347 #[doc(hidden)]
348 pub description: Option<ArcStr>,
349 #[doc(hidden)]
350 pub input_fields: Vec<Argument<S>>,
351 #[debug(ignore)]
352 pub(crate) try_parse_fn: InputValueParseFn<S>,
353}
354
355impl<S> InputObjectMeta<S> {
356 pub fn new<T>(name: impl Into<ArcStr>, input_fields: &[Argument<S>]) -> Self
358 where
359 T: FromInputValue<S>,
360 T::Error: IntoFieldError<S>,
361 S: Clone,
362 {
363 Self {
364 name: name.into(),
365 description: None,
366 input_fields: input_fields.to_vec(),
367 try_parse_fn: try_parse_fn::<S, T>,
368 }
369 }
370
371 #[must_use]
375 pub fn description(mut self, description: impl Into<ArcStr>) -> Self {
376 self.description = Some(description.into());
377 self
378 }
379
380 pub fn into_meta(self) -> MetaType<S> {
382 MetaType::InputObject(self)
383 }
384}
385
386#[derive(Debug)]
391pub struct PlaceholderMeta {
392 #[doc(hidden)]
393 pub of_type: Type,
394}
395
396#[derive(Debug, Clone)]
398pub struct Field<S> {
399 #[doc(hidden)]
400 pub name: ArcStr,
401 #[doc(hidden)]
402 pub description: Option<ArcStr>,
403 #[doc(hidden)]
404 pub arguments: Option<Vec<Argument<S>>>,
405 #[doc(hidden)]
406 pub field_type: Type,
407 #[doc(hidden)]
408 pub deprecation_status: DeprecationStatus,
409}
410
411impl<S> Field<S> {
412 #[must_use]
416 pub fn description(mut self, description: impl Into<ArcStr>) -> Self {
417 self.description = Some(description.into());
418 self
419 }
420
421 #[must_use]
425 pub fn argument(mut self, argument: Argument<S>) -> Self {
426 match self.arguments {
427 None => {
428 self.arguments = Some(vec![argument]);
429 }
430 Some(ref mut args) => {
431 args.push(argument);
432 }
433 };
434 self
435 }
436
437 #[must_use]
439 pub fn is_builtin(&self) -> bool {
440 self.name.starts_with("__")
442 }
443
444 #[must_use]
448 pub fn deprecated(mut self, reason: Option<impl Into<ArcStr>>) -> Self {
449 self.deprecation_status = DeprecationStatus::Deprecated(reason.map(Into::into));
450 self
451 }
452}
453
454#[derive(Debug, Clone)]
456pub struct Argument<S> {
457 #[doc(hidden)]
458 pub name: ArcStr,
459 #[doc(hidden)]
460 pub description: Option<ArcStr>,
461 #[doc(hidden)]
462 pub arg_type: Type,
463 #[doc(hidden)]
464 pub default_value: Option<InputValue<S>>,
465}
466
467impl<S> Argument<S> {
468 pub fn new(name: impl Into<ArcStr>, arg_type: Type) -> Self {
470 Self {
471 name: name.into(),
472 description: None,
473 arg_type,
474 default_value: None,
475 }
476 }
477
478 #[must_use]
482 pub fn description(mut self, description: impl Into<ArcStr>) -> Self {
483 self.description = Some(description.into());
484 self
485 }
486
487 #[must_use]
489 pub fn is_builtin(&self) -> bool {
490 self.name.starts_with("__")
492 }
493
494 #[must_use]
498 pub fn default_value(mut self, val: InputValue<S>) -> Self {
499 self.default_value = Some(val);
500 self
501 }
502}
503
504#[derive(Debug, Clone)]
506pub struct EnumValue {
507 pub name: ArcStr,
511
512 pub description: Option<ArcStr>,
517
518 pub deprecation_status: DeprecationStatus,
520}
521
522impl EnumValue {
523 pub fn new(name: impl Into<ArcStr>) -> Self {
525 Self {
526 name: name.into(),
527 description: None,
528 deprecation_status: DeprecationStatus::Current,
529 }
530 }
531
532 #[must_use]
536 pub fn description(mut self, description: impl Into<ArcStr>) -> Self {
537 self.description = Some(description.into());
538 self
539 }
540
541 #[must_use]
545 pub fn deprecated(mut self, reason: Option<impl Into<ArcStr>>) -> Self {
546 self.deprecation_status = DeprecationStatus::Deprecated(reason.map(Into::into));
547 self
548 }
549}
550
551#[derive(Debug)]
553pub enum MetaType<S = DefaultScalarValue> {
554 #[doc(hidden)]
555 Scalar(ScalarMeta<S>),
556 #[doc(hidden)]
557 List(ListMeta),
558 #[doc(hidden)]
559 Nullable(NullableMeta),
560 #[doc(hidden)]
561 Object(ObjectMeta<S>),
562 #[doc(hidden)]
563 Enum(EnumMeta<S>),
564 #[doc(hidden)]
565 Interface(InterfaceMeta<S>),
566 #[doc(hidden)]
567 Union(UnionMeta),
568 #[doc(hidden)]
569 InputObject(InputObjectMeta<S>),
570 #[doc(hidden)]
571 Placeholder(PlaceholderMeta),
572}
573
574impl<S> MetaType<S> {
575 pub fn name(&self) -> Option<&ArcStr> {
580 match self {
581 Self::Enum(EnumMeta { name, .. })
582 | Self::InputObject(InputObjectMeta { name, .. })
583 | Self::Interface(InterfaceMeta { name, .. })
584 | Self::Object(ObjectMeta { name, .. })
585 | Self::Scalar(ScalarMeta { name, .. })
586 | Self::Union(UnionMeta { name, .. }) => Some(name),
587 Self::List(..) | Self::Nullable(..) | Self::Placeholder(..) => None,
588 }
589 }
590
591 pub fn description(&self) -> Option<&ArcStr> {
596 match self {
597 Self::Enum(EnumMeta { description, .. })
598 | Self::InputObject(InputObjectMeta { description, .. })
599 | Self::Interface(InterfaceMeta { description, .. })
600 | Self::Object(ObjectMeta { description, .. })
601 | Self::Scalar(ScalarMeta { description, .. })
602 | Self::Union(UnionMeta { description, .. }) => description.as_ref(),
603 Self::List(..) | Self::Nullable(..) | Self::Placeholder(..) => None,
604 }
605 }
606
607 pub fn specified_by_url(&self) -> Option<&ArcStr> {
613 match self {
614 Self::Scalar(ScalarMeta {
615 specified_by_url, ..
616 }) => specified_by_url.as_ref(),
617 Self::Enum(..)
618 | Self::InputObject(..)
619 | Self::Interface(..)
620 | Self::List(..)
621 | Self::Nullable(..)
622 | Self::Object(..)
623 | Self::Placeholder(..)
624 | Self::Union(..) => None,
625 }
626 }
627
628 pub fn type_kind(&self) -> TypeKind {
634 match self {
635 Self::Scalar(..) => TypeKind::Scalar,
636 Self::List(..) => TypeKind::List,
637 Self::Nullable(..) => panic!("сan't take `type_kind` of `MetaType::Nullable`"),
638 Self::Object(..) => TypeKind::Object,
639 Self::Enum(..) => TypeKind::Enum,
640 Self::Interface(..) => TypeKind::Interface,
641 Self::Union(..) => TypeKind::Union,
642 Self::InputObject(..) => TypeKind::InputObject,
643 Self::Placeholder(..) => panic!("сan't take `type_kind` of `MetaType::Placeholder`"),
644 }
645 }
646
647 pub fn field_by_name(&self, name: &str) -> Option<&Field<S>> {
651 match self {
652 Self::Interface(InterfaceMeta { fields, .. })
653 | Self::Object(ObjectMeta { fields, .. }) => fields.iter().find(|f| f.name == name),
654 Self::Enum(..)
655 | Self::InputObject(..)
656 | Self::List(..)
657 | Self::Nullable(..)
658 | Self::Placeholder(..)
659 | Self::Scalar(..)
660 | Self::Union(..) => None,
661 }
662 }
663
664 pub fn input_field_by_name(&self, name: &str) -> Option<&Argument<S>> {
668 match self {
669 Self::InputObject(InputObjectMeta { input_fields, .. }) => {
670 input_fields.iter().find(|f| f.name == name)
671 }
672 Self::Enum(..)
673 | Self::Interface(..)
674 | Self::List(..)
675 | Self::Nullable(..)
676 | Self::Object(..)
677 | Self::Placeholder(..)
678 | Self::Scalar(..)
679 | Self::Union(..) => None,
680 }
681 }
682
683 pub fn as_type(&self) -> Type {
685 match self {
686 Self::Enum(EnumMeta { name, .. })
687 | Self::InputObject(InputObjectMeta { name, .. })
688 | Self::Interface(InterfaceMeta { name, .. })
689 | Self::Object(ObjectMeta { name, .. })
690 | Self::Scalar(ScalarMeta { name, .. })
691 | Self::Union(UnionMeta { name, .. }) => Type::nullable(name.clone()).wrap_non_null(),
692 Self::List(ListMeta {
693 of_type,
694 expected_size,
695 }) => of_type.clone().wrap_list(*expected_size).wrap_non_null(),
696 Self::Nullable(NullableMeta { of_type }) => of_type.clone().into_nullable(),
697 Self::Placeholder(PlaceholderMeta { of_type }) => of_type.clone(),
698 }
699 }
700
701 pub fn input_value_parse_fn(&self) -> Option<InputValueParseFn<S>> {
706 match self {
707 Self::Enum(EnumMeta { try_parse_fn, .. })
708 | Self::InputObject(InputObjectMeta { try_parse_fn, .. })
709 | Self::Scalar(ScalarMeta { try_parse_fn, .. }) => Some(*try_parse_fn),
710 Self::Interface(..)
711 | Self::List(..)
712 | Self::Nullable(..)
713 | Self::Object(..)
714 | Self::Placeholder(..)
715 | Self::Union(..) => None,
716 }
717 }
718
719 pub fn is_composite(&self) -> bool {
724 matches!(
725 self,
726 Self::Interface(..) | Self::Object(..) | Self::Union(..)
727 )
728 }
729
730 pub fn is_leaf(&self) -> bool {
734 matches!(self, Self::Enum(..) | Self::Scalar(..))
735 }
736
737 pub fn is_abstract(&self) -> bool {
741 matches!(self, Self::Interface(..) | Self::Union(..))
742 }
743
744 pub fn is_input(&self) -> bool {
750 matches!(
751 self,
752 Self::Enum(..) | Self::InputObject(..) | Self::Scalar(..)
753 )
754 }
755
756 pub fn is_builtin(&self) -> bool {
758 if let Some(name) = self.name() {
759 {
761 name.starts_with("__") ||
762 name == "Boolean" || name == "String" || name == "Int" || name == "Float" || name == "ID" ||
764 name == "_EmptyMutation" || name == "_EmptySubscription"
766 }
767 } else {
768 false
769 }
770 }
771
772 pub(crate) fn fields<'s>(&self, schema: &'s SchemaType<S>) -> Option<Vec<&'s Field<S>>> {
773 schema
774 .lookup_type(&self.as_type())
775 .and_then(|tpe| match tpe {
776 Self::Interface(i) => Some(i.fields.iter().collect()),
777 Self::Object(o) => Some(o.fields.iter().collect()),
778 Self::Union(u) => Some(
779 u.of_type_names
780 .iter()
781 .filter_map(|n| schema.concrete_type_by_name(n))
782 .filter_map(|t| t.fields(schema))
783 .flatten()
784 .collect(),
785 ),
786 Self::Enum(..)
787 | Self::InputObject(..)
788 | Self::List(..)
789 | Self::Nullable(..)
790 | Self::Placeholder(..)
791 | Self::Scalar(..) => None,
792 })
793 }
794}
795
796fn try_parse_fn<S, T>(v: &InputValue<S>) -> Result<(), FieldError<S>>
797where
798 T: FromInputValue<S>,
799 T::Error: IntoFieldError<S>,
800{
801 T::from_input_value(v)
802 .map_err(T::Error::into_field_error)
803 .map(drop)
804}