use std::fmt;
use crate::{Directive, FieldDefinition, StringValue};
#[derive(Debug, Clone)]
pub struct InterfaceDefinition {
name: String,
description: Option<StringValue>,
interfaces: Vec<String>,
fields: Vec<FieldDefinition>,
directives: Vec<Directive>,
extend: bool,
}
impl InterfaceDefinition {
pub fn new(name: String) -> Self {
Self {
name,
description: None,
fields: Vec::new(),
interfaces: Vec::new(),
directives: Vec::new(),
extend: false,
}
}
pub fn description(&mut self, description: String) {
self.description = Some(StringValue::Top {
source: description,
});
}
pub fn interface(&mut self, interface: String) {
self.interfaces.push(interface)
}
pub fn extend(&mut self) {
self.extend = true;
}
pub fn field(&mut self, field: FieldDefinition) {
self.fields.push(field)
}
pub fn directive(&mut self, directive: Directive) {
self.directives.push(directive)
}
}
impl fmt::Display for InterfaceDefinition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.extend {
write!(f, "extend ")?;
} else {
if let Some(description) = &self.description {
writeln!(f, "{description}")?;
}
}
write!(f, "interface {}", &self.name)?;
for (i, interface) in self.interfaces.iter().enumerate() {
match i {
0 => write!(f, " implements {interface}")?,
_ => write!(f, "& {interface}")?,
}
}
for directive in &self.directives {
write!(f, " {directive}")?;
}
write!(f, " {{")?;
for field in &self.fields {
write!(f, "\n{field}")?;
}
writeln!(f, "\n}}")
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Argument, Type_, Value};
use indoc::indoc;
use pretty_assertions::assert_eq;
#[test]
fn it_encodes_interfaces() {
let ty_1 = Type_::NamedType {
name: "String".to_string(),
};
let ty_2 = Type_::NamedType {
name: "String".to_string(),
};
let ty_3 = Type_::NonNull { ty: Box::new(ty_2) };
let ty_4 = Type_::List { ty: Box::new(ty_3) };
let ty_5 = Type_::NonNull { ty: Box::new(ty_4) };
let ty_6 = Type_::NamedType {
name: "Boolean".to_string(),
};
let mut field_1 = FieldDefinition::new("main".to_string(), ty_1);
field_1.description("Cat's main dish of a meal.".to_string());
let mut field_2 = FieldDefinition::new("snack".to_string(), ty_5);
field_2.description("Cat's post meal snack.".to_string());
let mut field_3 = FieldDefinition::new("pats".to_string(), ty_6);
field_3.description("Does cat get a pat\nafter meal?".to_string());
let mut directive = Directive::new(String::from("testDirective"));
directive.arg(Argument::new(
String::from("first"),
Value::String("one".to_string()),
));
let mut interface = InterfaceDefinition::new("Meal".to_string());
interface.description("Meal interface for various\nmeals during the day.".to_string());
interface.field(field_1);
interface.field(field_2);
interface.field(field_3);
interface.directive(directive);
assert_eq!(
interface.to_string(),
indoc! { r#"
"""
Meal interface for various
meals during the day.
"""
interface Meal @testDirective(first: "one") {
"Cat's main dish of a meal."
main: String
"Cat's post meal snack."
snack: [String!]!
"""
Does cat get a pat
after meal?
"""
pats: Boolean
}
"# }
);
}
#[test]
fn it_encodes_interface_extension() {
let ty_1 = Type_::NamedType {
name: "String".to_string(),
};
let ty_2 = Type_::NamedType {
name: "String".to_string(),
};
let ty_3 = Type_::NonNull { ty: Box::new(ty_2) };
let ty_4 = Type_::List { ty: Box::new(ty_3) };
let ty_5 = Type_::NonNull { ty: Box::new(ty_4) };
let ty_6 = Type_::NamedType {
name: "Boolean".to_string(),
};
let mut field_1 = FieldDefinition::new("main".to_string(), ty_1);
field_1.description("Cat's main dish of a meal.".to_string());
let mut field_2 = FieldDefinition::new("snack".to_string(), ty_5);
field_2.description("Cat's post meal snack.".to_string());
let mut field_3 = FieldDefinition::new("pats".to_string(), ty_6);
field_3.description("Does cat get a pat\nafter meal?".to_string());
let mut directive = Directive::new(String::from("testDirective"));
directive.arg(Argument::new(
String::from("first"),
Value::String("one".to_string()),
));
let mut interface = InterfaceDefinition::new("Meal".to_string());
interface.description("Meal interface for various\nmeals during the day.".to_string());
interface.field(field_1);
interface.field(field_2);
interface.field(field_3);
interface.directive(directive);
interface.extend();
assert_eq!(
interface.to_string(),
indoc! { r#"
extend interface Meal @testDirective(first: "one") {
"Cat's main dish of a meal."
main: String
"Cat's post meal snack."
snack: [String!]!
"""
Does cat get a pat
after meal?
"""
pats: Boolean
}
"# }
);
}
}