use std::sync::Arc;
use apollo_parser::{
ast::{self, SyntaxNodePtr},
SyntaxNode,
};
use ordered_float::{self, OrderedFloat};
use uuid::Uuid;
use crate::DocumentDatabase;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Definition {
OperationDefinition(OperationDefinition),
FragmentDefinition(FragmentDefinition),
DirectiveDefinition(DirectiveDefinition),
ScalarTypeDefinition(ScalarTypeDefinition),
ObjectTypeDefinition(ObjectTypeDefinition),
InterfaceTypeDefinition(InterfaceTypeDefinition),
UnionTypeDefinition(UnionTypeDefinition),
EnumTypeDefinition(EnumTypeDefinition),
InputObjectTypeDefinition(InputObjectTypeDefinition),
SchemaDefinition(SchemaDefinition),
SchemaExtension(SchemaExtension),
ScalarTypeExtension(ScalarTypeExtension),
ObjectTypeExtension(ObjectTypeExtension),
InterfaceTypeExtension(InterfaceTypeExtension),
UnionTypeExtension(UnionTypeExtension),
EnumTypeExtension(EnumTypeExtension),
InputObjectTypeExtension(InputObjectTypeExtension),
}
impl Definition {
pub fn name(&self) -> Option<&str> {
match self {
Definition::OperationDefinition(def) => def.name(),
Definition::FragmentDefinition(def) => Some(def.name()),
Definition::DirectiveDefinition(def) => Some(def.name()),
Definition::ScalarTypeDefinition(def) => Some(def.name()),
Definition::ObjectTypeDefinition(def) => Some(def.name()),
Definition::InterfaceTypeDefinition(def) => Some(def.name()),
Definition::UnionTypeDefinition(def) => Some(def.name()),
Definition::EnumTypeDefinition(def) => Some(def.name()),
Definition::InputObjectTypeDefinition(def) => Some(def.name()),
Definition::SchemaDefinition(_) => None,
Definition::SchemaExtension(_) => None,
Definition::ScalarTypeExtension(def) => Some(def.name()),
Definition::ObjectTypeExtension(def) => Some(def.name()),
Definition::InterfaceTypeExtension(def) => Some(def.name()),
Definition::UnionTypeExtension(def) => Some(def.name()),
Definition::EnumTypeExtension(def) => Some(def.name()),
Definition::InputObjectTypeExtension(def) => Some(def.name()),
}
}
pub fn name_src(&self) -> Option<&Name> {
match self {
Definition::OperationDefinition(def) => def.name_src(),
Definition::FragmentDefinition(def) => Some(def.name_src()),
Definition::DirectiveDefinition(def) => Some(def.name_src()),
Definition::ScalarTypeDefinition(def) => Some(def.name_src()),
Definition::ObjectTypeDefinition(def) => Some(def.name_src()),
Definition::InterfaceTypeDefinition(def) => Some(def.name_src()),
Definition::UnionTypeDefinition(def) => Some(def.name_src()),
Definition::EnumTypeDefinition(def) => Some(def.name_src()),
Definition::InputObjectTypeDefinition(def) => Some(def.name_src()),
Definition::SchemaDefinition(_) => None,
Definition::SchemaExtension(_) => None,
Definition::ScalarTypeExtension(def) => Some(def.name_src()),
Definition::ObjectTypeExtension(def) => Some(def.name_src()),
Definition::InterfaceTypeExtension(def) => Some(def.name_src()),
Definition::UnionTypeExtension(def) => Some(def.name_src()),
Definition::EnumTypeExtension(def) => Some(def.name_src()),
Definition::InputObjectTypeExtension(def) => Some(def.name_src()),
}
}
pub fn ty(&self) -> String {
match self {
Definition::OperationDefinition(_) => "OperationDefinition".to_string(),
Definition::FragmentDefinition(_) => "FragmentDefinition".to_string(),
Definition::DirectiveDefinition(_) => "DirectiveDefinition".to_string(),
Definition::ScalarTypeDefinition(_) => "ScalarTypeDefinition".to_string(),
Definition::ObjectTypeDefinition(_) => "ObjectTypeDefinition".to_string(),
Definition::InterfaceTypeDefinition(_) => "InterfaceTypeDefinition".to_string(),
Definition::UnionTypeDefinition(_) => "UnionTypeDefinition".to_string(),
Definition::EnumTypeDefinition(_) => "EnumTypeDefinition".to_string(),
Definition::InputObjectTypeDefinition(_) => "InputObjectTypeDefinition".to_string(),
Definition::SchemaDefinition(_) => "SchemaDefinition".to_string(),
Definition::SchemaExtension(_) => "SchemaExtension".to_string(),
Definition::ScalarTypeExtension(_) => "ScalarTypeExtension".to_string(),
Definition::ObjectTypeExtension(_) => "ObjectTypeExtension".to_string(),
Definition::InterfaceTypeExtension(_) => "InterfaceTypeExtension".to_string(),
Definition::UnionTypeExtension(_) => "UnionTypeExtension".to_string(),
Definition::EnumTypeExtension(_) => "EnumTypeExtension".to_string(),
Definition::InputObjectTypeExtension(_) => "InputObjectTypeExtension".to_string(),
}
}
pub fn id(&self) -> Option<&Uuid> {
match self {
Definition::OperationDefinition(def) => Some(def.id()),
Definition::FragmentDefinition(def) => Some(def.id()),
Definition::DirectiveDefinition(def) => Some(def.id()),
Definition::ScalarTypeDefinition(def) => Some(def.id()),
Definition::ObjectTypeDefinition(def) => Some(def.id()),
Definition::InterfaceTypeDefinition(def) => Some(def.id()),
Definition::UnionTypeDefinition(def) => Some(def.id()),
Definition::EnumTypeDefinition(def) => Some(def.id()),
Definition::InputObjectTypeDefinition(def) => Some(def.id()),
Definition::SchemaDefinition(_) => None,
Definition::SchemaExtension(_) => None,
Definition::ScalarTypeExtension(_) => None,
Definition::ObjectTypeExtension(_) => None,
Definition::InterfaceTypeExtension(_) => None,
Definition::UnionTypeExtension(_) => None,
Definition::EnumTypeExtension(_) => None,
Definition::InputObjectTypeExtension(_) => None,
}
}
pub fn field(&self, name: &str) -> Option<&FieldDefinition> {
match self {
Definition::ObjectTypeDefinition(def) => def.field(name),
Definition::InterfaceTypeDefinition(def) => def.field(name),
_ => None,
}
}
pub fn directives(&self) -> &[Directive] {
match self {
Definition::OperationDefinition(def) => def.directives(),
Definition::FragmentDefinition(def) => def.directives(),
Definition::DirectiveDefinition(_) => &[],
Definition::ScalarTypeDefinition(def) => def.directives(),
Definition::ObjectTypeDefinition(def) => def.directives(),
Definition::InterfaceTypeDefinition(def) => def.directives(),
Definition::UnionTypeDefinition(def) => def.directives(),
Definition::EnumTypeDefinition(def) => def.directives(),
Definition::InputObjectTypeDefinition(def) => def.directives(),
Definition::SchemaDefinition(def) => def.directives(),
Definition::SchemaExtension(def) => def.directives(),
Definition::ScalarTypeExtension(def) => def.directives(),
Definition::ObjectTypeExtension(def) => def.directives(),
Definition::InterfaceTypeExtension(def) => def.directives(),
Definition::UnionTypeExtension(def) => def.directives(),
Definition::EnumTypeExtension(def) => def.directives(),
Definition::InputObjectTypeExtension(def) => def.directives(),
}
}
#[must_use]
pub fn is_output_definition(&self) -> bool {
matches!(
self,
Self::ScalarTypeDefinition(..)
| Self::ObjectTypeDefinition(..)
| Self::InterfaceTypeDefinition(..)
| Self::UnionTypeDefinition(..)
| Self::EnumTypeDefinition(..)
)
}
#[must_use]
pub fn is_input_definition(&self) -> bool {
matches!(
self,
Self::ScalarTypeDefinition(..)
| Self::EnumTypeDefinition(..)
| Self::InputObjectTypeDefinition(..)
)
}
#[must_use]
pub fn is_operation_definition(&self) -> bool {
matches!(self, Self::OperationDefinition(..))
}
#[must_use]
pub fn is_fragment_definition(&self) -> bool {
matches!(self, Self::FragmentDefinition(..))
}
#[must_use]
pub fn is_directive_definition(&self) -> bool {
matches!(self, Self::DirectiveDefinition(..))
}
#[must_use]
pub fn is_scalar_type_definition(&self) -> bool {
matches!(self, Self::ScalarTypeDefinition(..))
}
#[must_use]
pub fn is_object_type_definition(&self) -> bool {
matches!(self, Self::ObjectTypeDefinition { .. })
}
#[must_use]
pub fn is_interface_type_definition(&self) -> bool {
matches!(self, Self::InterfaceTypeDefinition(..))
}
#[must_use]
pub fn is_union_type_definition(&self) -> bool {
matches!(self, Self::UnionTypeDefinition(..))
}
#[must_use]
pub fn is_enum_type_definition(&self) -> bool {
matches!(self, Self::EnumTypeDefinition(..))
}
#[must_use]
pub fn is_input_object_type_definition(&self) -> bool {
matches!(self, Self::InputObjectTypeDefinition(..))
}
#[must_use]
pub fn is_schema_definition(&self) -> bool {
matches!(self, Self::SchemaDefinition(..))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct FragmentDefinition {
pub(crate) id: Uuid,
pub(crate) name: Name,
pub(crate) type_condition: String,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) selection_set: SelectionSet,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl FragmentDefinition {
pub fn id(&self) -> &Uuid {
&self.id
}
pub fn name(&self) -> &str {
self.name.src()
}
pub fn name_src(&self) -> &Name {
&self.name
}
pub fn type_condition(&self) -> &str {
self.type_condition.as_ref()
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn selection_set(&self) -> &SelectionSet {
&self.selection_set
}
pub fn variables(&self, db: &dyn DocumentDatabase) -> Vec<Variable> {
self.selection_set
.selection()
.iter()
.flat_map(|sel| sel.variables(db))
.collect()
}
pub fn ty(&self, db: &dyn DocumentDatabase) -> Option<Arc<Definition>> {
db.find_type_system_definition_by_name(self.name().to_string())
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct OperationDefinition {
pub(crate) id: Uuid,
pub(crate) operation_ty: OperationType,
pub(crate) name: Option<Name>,
pub(crate) variables: Arc<Vec<VariableDefinition>>,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) selection_set: SelectionSet,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl OperationDefinition {
pub fn id(&self) -> &Uuid {
&self.id
}
pub fn operation_ty(&self) -> &OperationType {
&self.operation_ty
}
pub fn name(&self) -> Option<&str> {
self.name.as_ref().map(|n| n.src())
}
pub fn name_src(&self) -> Option<&Name> {
self.name.as_ref()
}
pub fn object_type(&self, db: &dyn DocumentDatabase) -> Option<Arc<ObjectTypeDefinition>> {
match self.operation_ty {
OperationType::Query => db.schema().query(db),
OperationType::Mutation => db.schema().mutation(db),
OperationType::Subscription => db.schema().subscription(db),
}
}
pub fn variables(&self) -> &[VariableDefinition] {
self.variables.as_ref()
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn selection_set(&self) -> &SelectionSet {
&self.selection_set
}
pub fn fields(&self, db: &dyn DocumentDatabase) -> Arc<Vec<Field>> {
db.operation_fields(self.id)
}
pub fn fields_in_inline_fragments(&self, db: &dyn DocumentDatabase) -> Arc<Vec<Field>> {
db.operation_inline_fragment_fields(self.id)
}
pub fn fields_in_fragment_spread(&self, db: &dyn DocumentDatabase) -> Arc<Vec<Field>> {
db.operation_fragment_spread_fields(self.id)
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum OperationType {
Query,
Mutation,
Subscription,
}
impl OperationType {
#[must_use]
pub fn is_query(&self) -> bool {
matches!(self, Self::Query)
}
#[must_use]
pub fn is_mutation(&self) -> bool {
matches!(self, Self::Mutation)
}
#[must_use]
pub fn is_subscription(&self) -> bool {
matches!(self, Self::Subscription)
}
}
impl std::fmt::Display for OperationType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
OperationType::Query => write!(f, "Query"),
OperationType::Mutation => write!(f, "Mutation"),
OperationType::Subscription => write!(f, "Subscription"),
}
}
}
impl From<OperationType> for String {
fn from(op_type: OperationType) -> Self {
if op_type.is_subscription() {
"Subscription".to_string()
} else if op_type.is_mutation() {
"Mutation".to_string()
} else {
"Query".to_string()
}
}
}
impl<'a> From<&'a str> for OperationType {
fn from(op_type: &str) -> Self {
if op_type == "Query" {
OperationType::Query
} else if op_type == "Mutation" {
OperationType::Mutation
} else {
OperationType::Subscription
}
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct VariableDefinition {
pub(crate) name: Name,
pub(crate) ty: Type,
pub(crate) default_value: Option<DefaultValue>,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl VariableDefinition {
pub fn name(&self) -> &str {
self.name.src()
}
pub fn ty(&self) -> &Type {
&self.ty
}
pub fn default_value(&self) -> Option<&DefaultValue> {
self.default_value.as_ref()
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum Type {
NonNull {
ty: Box<Type>,
ast_ptr: Option<SyntaxNodePtr>,
},
List {
ty: Box<Type>,
ast_ptr: Option<SyntaxNodePtr>,
},
Named {
name: String,
ast_ptr: Option<SyntaxNodePtr>,
},
}
impl Type {
#[must_use]
pub fn is_non_null(&self) -> bool {
matches!(self, Self::NonNull { .. })
}
#[must_use]
pub fn is_named(&self) -> bool {
matches!(self, Self::Named { .. })
}
#[must_use]
pub fn is_list(&self) -> bool {
matches!(self, Self::List { .. })
}
#[must_use]
pub fn is_output_type(&self, db: &dyn DocumentDatabase) -> bool {
if let Some(ty) = self.ty(db) {
ty.as_ref().is_output_definition()
} else {
false
}
}
#[must_use]
pub fn is_input_type(&self, db: &dyn DocumentDatabase) -> bool {
if let Some(ty) = self.ty(db) {
ty.as_ref().is_input_definition()
} else {
false
}
}
pub fn ast_ptr(&self) -> Option<&SyntaxNodePtr> {
match self {
Type::NonNull { ty: _, ast_ptr } => ast_ptr.as_ref(),
Type::List { ty: _, ast_ptr } => ast_ptr.as_ref(),
Type::Named { name: _, ast_ptr } => ast_ptr.as_ref(),
}
}
pub fn ty(&self, db: &dyn DocumentDatabase) -> Option<Arc<Definition>> {
db.find_definition_by_name(self.name())
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> Option<SyntaxNode> {
self.ast_ptr()
.map(|ptr| ptr.to_node(&rowan::SyntaxNode::new_root(db.document())))
}
pub fn name(&self) -> String {
match self {
Type::NonNull { ty, ast_ptr: _ } => get_name(*ty.clone()),
Type::List { ty, ast_ptr: _ } => get_name(*ty.clone()),
Type::Named { name, ast_ptr: _ } => name.to_owned(),
}
}
}
fn get_name(ty: Type) -> String {
match ty {
Type::NonNull { ty, ast_ptr: _ } => match *ty {
Type::NonNull { ty, ast_ptr: _ } => get_name(*ty),
Type::List { ty, ast_ptr: _ } => get_name(*ty),
Type::Named { name, ast_ptr: _ } => name,
},
Type::List { ty, ast_ptr: _ } => match *ty {
Type::NonNull { ty, ast_ptr: _ } => get_name(*ty),
Type::List { ty, ast_ptr: _ } => get_name(*ty),
Type::Named { name, ast_ptr: _ } => name,
},
Type::Named { name, ast_ptr: _ } => name,
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Directive {
pub(crate) name: Name,
pub(crate) arguments: Arc<Vec<Argument>>,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl Directive {
pub fn name(&self) -> &str {
self.name.src()
}
pub fn arguments(&self) -> &[Argument] {
self.arguments.as_ref()
}
pub fn argument_by_name(&self, name: &str) -> Option<&Value> {
Some(
self.arguments
.iter()
.find(|arg| arg.name() == name)?
.value(),
)
}
pub fn directive(&self, db: &dyn DocumentDatabase) -> Option<Arc<DirectiveDefinition>> {
db.find_directive_definition_by_name(self.name().to_string())
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct DirectiveDefinition {
pub(crate) id: Uuid,
pub(crate) description: Option<String>,
pub(crate) name: Name,
pub(crate) arguments: ArgumentsDefinition,
pub(crate) repeatable: bool,
pub(crate) directive_locations: Arc<Vec<DirectiveLocation>>,
pub(crate) ast_ptr: Option<SyntaxNodePtr>,
}
impl DirectiveDefinition {
pub fn name(&self) -> &str {
self.name.src()
}
pub fn name_src(&self) -> &Name {
&self.name
}
pub fn description(&self) -> Option<&str> {
self.description.as_deref()
}
pub fn id(&self) -> &Uuid {
&self.id
}
pub fn arguments(&self) -> &ArgumentsDefinition {
&self.arguments
}
pub fn directive_locations(&self) -> &[DirectiveLocation] {
self.directive_locations.as_ref()
}
pub fn repeatable(&self) -> bool {
self.repeatable
}
pub fn ast_ptr(&self) -> Option<&SyntaxNodePtr> {
self.ast_ptr.as_ref()
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> Option<SyntaxNode> {
self.ast_ptr()
.map(|ptr| ptr.to_node(&rowan::SyntaxNode::new_root(db.document())))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum DirectiveLocation {
Query,
Mutation,
Subscription,
Field,
FragmentDefinition,
FragmentSpread,
InlineFragment,
VariableDefinition,
Schema,
Scalar,
Object,
FieldDefinition,
ArgumentDefinition,
Interface,
Union,
Enum,
EnumValue,
InputObject,
InputFieldDefinition,
}
impl From<ast::DirectiveLocation> for DirectiveLocation {
fn from(directive_loc: ast::DirectiveLocation) -> Self {
if directive_loc.query_token().is_some() {
DirectiveLocation::Query
} else if directive_loc.mutation_token().is_some() {
DirectiveLocation::Mutation
} else if directive_loc.subscription_token().is_some() {
DirectiveLocation::Subscription
} else if directive_loc.field_token().is_some() {
DirectiveLocation::Field
} else if directive_loc.fragment_definition_token().is_some() {
DirectiveLocation::FragmentDefinition
} else if directive_loc.fragment_spread_token().is_some() {
DirectiveLocation::FragmentSpread
} else if directive_loc.inline_fragment_token().is_some() {
DirectiveLocation::InlineFragment
} else if directive_loc.variable_definition_token().is_some() {
DirectiveLocation::VariableDefinition
} else if directive_loc.schema_token().is_some() {
DirectiveLocation::Schema
} else if directive_loc.scalar_token().is_some() {
DirectiveLocation::Scalar
} else if directive_loc.object_token().is_some() {
DirectiveLocation::Object
} else if directive_loc.field_definition_token().is_some() {
DirectiveLocation::FieldDefinition
} else if directive_loc.argument_definition_token().is_some() {
DirectiveLocation::ArgumentDefinition
} else if directive_loc.interface_token().is_some() {
DirectiveLocation::Interface
} else if directive_loc.union_token().is_some() {
DirectiveLocation::Union
} else if directive_loc.enum_token().is_some() {
DirectiveLocation::Enum
} else if directive_loc.enum_value_token().is_some() {
DirectiveLocation::EnumValue
} else if directive_loc.input_object_token().is_some() {
DirectiveLocation::InputObject
} else {
DirectiveLocation::InputFieldDefinition
}
}
}
impl From<DirectiveLocation> for String {
fn from(dir_loc: DirectiveLocation) -> Self {
match dir_loc {
DirectiveLocation::Query => "QUERY".to_string(),
DirectiveLocation::Mutation => "MUTATION".to_string(),
DirectiveLocation::Subscription => "SUBSCRIPTION".to_string(),
DirectiveLocation::Field => "FIELD".to_string(),
DirectiveLocation::FragmentDefinition => "FRAGMENT_DEFINITION".to_string(),
DirectiveLocation::FragmentSpread => "FRAGMENT_SPREAD".to_string(),
DirectiveLocation::InlineFragment => "INLINE_FRAGMENT".to_string(),
DirectiveLocation::VariableDefinition => "VARIABLE_DEFINITION".to_string(),
DirectiveLocation::Schema => "SCHEMA".to_string(),
DirectiveLocation::Scalar => "SCALAR".to_string(),
DirectiveLocation::Object => "OBJECT".to_string(),
DirectiveLocation::FieldDefinition => "FIELD_DEFINITION".to_string(),
DirectiveLocation::ArgumentDefinition => "ARGUMENT_DEFINITION".to_string(),
DirectiveLocation::Interface => "INTERFACE".to_string(),
DirectiveLocation::Union => "UNION".to_string(),
DirectiveLocation::Enum => "ENUM".to_string(),
DirectiveLocation::EnumValue => "ENUM_VALUE".to_string(),
DirectiveLocation::InputObject => "INPUT_OBJECT".to_string(),
DirectiveLocation::InputFieldDefinition => "INPUT_FIELD_DEFINITION".to_string(),
}
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Argument {
pub(crate) name: Name,
pub(crate) value: Value,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl Argument {
pub fn value(&self) -> &Value {
&self.value
}
pub fn name(&self) -> &str {
self.name.src()
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
pub type DefaultValue = Value;
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum Value {
Variable(Variable),
Int(Float),
Float(Float),
String(String),
Boolean(bool),
Null,
Enum(Name),
List(Vec<Value>),
Object(Vec<(Name, Value)>),
}
impl Value {
#[must_use]
pub fn is_variable(&self) -> bool {
matches!(self, Self::Variable(..))
}
}
impl TryFrom<Value> for f64 {
type Error = FloatCoercionError;
#[inline]
fn try_from(value: Value) -> Result<Self, Self::Error> {
f64::try_from(&value)
}
}
impl TryFrom<&'_ Value> for f64 {
type Error = FloatCoercionError;
fn try_from(value: &'_ Value) -> Result<Self, Self::Error> {
if let Value::Int(float) | Value::Float(float) = value {
Ok(float.inner.0)
} else {
Err(FloatCoercionError(()))
}
}
}
#[derive(thiserror::Error, Debug)]
#[error("coercing a non-numeric value to a `Float` input value")]
pub struct FloatCoercionError(());
impl TryFrom<Value> for i32 {
type Error = IntCoercionError;
#[inline]
fn try_from(value: Value) -> Result<Self, Self::Error> {
i32::try_from(&value)
}
}
impl TryFrom<&'_ Value> for i32 {
type Error = IntCoercionError;
fn try_from(value: &'_ Value) -> Result<Self, Self::Error> {
if let Value::Int(float) = value {
float
.to_i32_checked()
.ok_or(IntCoercionError::RangeOverflow)
} else {
Err(IntCoercionError::NotAnInteger)
}
}
}
#[derive(thiserror::Error, Debug)]
pub enum IntCoercionError {
#[error("coercing a non-integer value to an `Int` input value")]
NotAnInteger,
#[error("integer input value overflows the signed 32-bit range")]
RangeOverflow,
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Variable {
pub(crate) name: String,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl Variable {
pub fn name(&self) -> &str {
self.name.as_ref()
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct SelectionSet {
pub(crate) selection: Arc<Vec<Selection>>,
}
impl SelectionSet {
pub fn selection(&self) -> &[Selection] {
self.selection.as_ref()
}
pub fn fields(&self) -> Vec<Field> {
let fields: Vec<Field> = self
.selection()
.iter()
.filter_map(|sel| match sel {
Selection::Field(field) => return Some(field.as_ref().clone()),
_ => None,
})
.collect();
fields
}
pub fn fragment_spreads(&self) -> Vec<FragmentSpread> {
let fragment_spread: Vec<FragmentSpread> = self
.selection()
.iter()
.filter_map(|sel| match sel {
Selection::FragmentSpread(fragment_spread) => {
return Some(fragment_spread.as_ref().clone())
}
_ => None,
})
.collect();
fragment_spread
}
pub fn inline_fragments(&self) -> Vec<InlineFragment> {
let inline_fragments: Vec<InlineFragment> = self
.selection()
.iter()
.filter_map(|sel| match sel {
Selection::InlineFragment(inline) => return Some(inline.as_ref().clone()),
_ => None,
})
.collect();
inline_fragments
}
pub fn field(&self, name: &str) -> Option<&Field> {
self.selection().iter().find_map(|sel| {
if let Selection::Field(field) = sel {
if field.name() == name {
return Some(field.as_ref());
}
None
} else {
None
}
})
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum Selection {
Field(Arc<Field>),
FragmentSpread(Arc<FragmentSpread>),
InlineFragment(Arc<InlineFragment>),
}
impl Selection {
pub fn variables(&self, db: &dyn DocumentDatabase) -> Vec<Variable> {
match self {
Selection::Field(field) => field.variables(db),
Selection::FragmentSpread(fragment_spread) => fragment_spread.variables(db),
Selection::InlineFragment(inline_fragment) => inline_fragment.variables(db),
}
}
#[must_use]
pub fn is_field(&self) -> bool {
matches!(self, Self::Field(..))
}
#[must_use]
pub fn is_fragment_spread(&self) -> bool {
matches!(self, Self::FragmentSpread(..))
}
#[must_use]
pub fn is_inline_fragment(&self) -> bool {
matches!(self, Self::InlineFragment(..))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Field {
pub(crate) alias: Option<Arc<Alias>>,
pub(crate) name: Name,
pub(crate) arguments: Arc<Vec<Argument>>,
pub(crate) parent_obj: Option<String>,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) selection_set: SelectionSet,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl Field {
pub fn alias(&self) -> Option<&Alias> {
match &self.alias {
Some(alias) => Some(alias.as_ref()),
None => None,
}
}
pub fn name(&self) -> &str {
self.name.src()
}
pub fn ty(&self, db: &dyn DocumentDatabase) -> Option<Type> {
let def = db
.find_type_system_definition_by_name(self.parent_obj.as_ref()?.to_string())?
.field(self.name())?
.ty()
.to_owned();
Some(def)
}
pub fn field_definition(&self, db: &dyn DocumentDatabase) -> Option<FieldDefinition> {
db.find_object_type_by_name(self.parent_obj.as_ref()?.to_string())?
.fields_definition()
.iter()
.find(|field| field.name() == self.name())
.cloned()
}
pub fn arguments(&self) -> &[Argument] {
self.arguments.as_ref()
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn selection_set(&self) -> &SelectionSet {
&self.selection_set
}
pub fn variables(&self, db: &dyn DocumentDatabase) -> Vec<Variable> {
let mut vars: Vec<_> = self
.arguments
.iter()
.filter_map(|arg| match arg.value() {
Value::Variable(var) => Some(var.clone()),
_ => None,
})
.collect();
let iter = self
.selection_set
.selection()
.iter()
.flat_map(|sel| sel.variables(db));
vars.extend(iter);
vars
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct InlineFragment {
pub(crate) type_condition: Option<Name>,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) selection_set: SelectionSet,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl InlineFragment {
pub fn type_condition(&self) -> Option<&str> {
self.type_condition.as_ref().map(|t| t.src())
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn selection_set(&self) -> &SelectionSet {
&self.selection_set
}
pub fn variables(&self, db: &dyn DocumentDatabase) -> Vec<Variable> {
let vars = self
.selection_set
.selection()
.iter()
.flat_map(|sel| sel.variables(db))
.collect();
vars
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct FragmentSpread {
pub(crate) name: Name,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl FragmentSpread {
pub fn name(&self) -> &str {
self.name.src()
}
pub fn fragment(&self, db: &dyn DocumentDatabase) -> Option<Arc<FragmentDefinition>> {
db.find_fragment_by_name(self.name().to_string())
}
pub fn variables(&self, db: &dyn DocumentDatabase) -> Vec<Variable> {
let vars = match self.fragment(db) {
Some(fragment) => fragment
.selection_set
.selection()
.iter()
.flat_map(|sel| sel.variables(db))
.collect(),
None => Vec::new(),
};
vars
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Alias(pub String);
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct Float {
inner: ordered_float::OrderedFloat<f64>,
}
impl Float {
pub fn new(float: f64) -> Self {
Self {
inner: OrderedFloat(float),
}
}
pub fn get(self) -> f64 {
self.inner.0
}
pub fn to_i32_checked(self) -> Option<i32> {
let float = self.inner.0;
if float <= (i32::MAX as f64) && float >= (i32::MIN as f64) {
Some(float as i32)
} else {
None
}
}
}
#[derive(Clone, Debug, Hash, PartialEq, Default, Eq)]
pub struct SchemaDefinition {
pub(crate) description: Option<String>,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) root_operation_type_definition: Arc<Vec<RootOperationTypeDefinition>>,
pub(crate) ast_ptr: Option<SyntaxNodePtr>,
}
impl SchemaDefinition {
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn root_operation_type_definition(&self) -> &[RootOperationTypeDefinition] {
self.root_operation_type_definition.as_ref()
}
pub(crate) fn set_root_operation_type_definition(&mut self, op: RootOperationTypeDefinition) {
Arc::get_mut(&mut self.root_operation_type_definition)
.unwrap()
.push(op)
}
pub fn ast_ptr(&self) -> Option<&SyntaxNodePtr> {
self.ast_ptr.as_ref()
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> Option<SyntaxNode> {
self.ast_ptr()
.map(|ptr| ptr.to_node(&rowan::SyntaxNode::new_root(db.document())))
}
pub fn query(&self, db: &dyn DocumentDatabase) -> Option<Arc<ObjectTypeDefinition>> {
self.root_operation_type_definition().iter().find_map(|op| {
if op.operation_type.is_query() {
op.object_type(db)
} else {
None
}
})
}
pub fn mutation(&self, db: &dyn DocumentDatabase) -> Option<Arc<ObjectTypeDefinition>> {
self.root_operation_type_definition().iter().find_map(|op| {
if op.operation_type.is_mutation() {
op.object_type(db)
} else {
None
}
})
}
pub fn subscription(&self, db: &dyn DocumentDatabase) -> Option<Arc<ObjectTypeDefinition>> {
self.root_operation_type_definition().iter().find_map(|op| {
if op.operation_type.is_subscription() {
op.object_type(db)
} else {
None
}
})
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct RootOperationTypeDefinition {
pub(crate) operation_type: OperationType,
pub(crate) named_type: Type,
pub(crate) ast_ptr: Option<SyntaxNodePtr>,
}
impl RootOperationTypeDefinition {
pub fn named_type(&self) -> &Type {
&self.named_type
}
pub fn operation_type(&self) -> OperationType {
self.operation_type
}
pub fn object_type(&self, db: &dyn DocumentDatabase) -> Option<Arc<ObjectTypeDefinition>> {
db.find_object_type_by_name(self.named_type().name())
}
pub fn object_type_id(&self, db: &dyn DocumentDatabase) -> Option<Uuid> {
self.object_type(db).map(|object_type| *object_type.id())
}
pub fn ast_ptr(&self) -> Option<&SyntaxNodePtr> {
self.ast_ptr.as_ref()
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> Option<SyntaxNode> {
self.ast_ptr()
.map(|ptr| ptr.to_node(&rowan::SyntaxNode::new_root(db.document())))
}
}
impl Default for RootOperationTypeDefinition {
fn default() -> Self {
Self {
operation_type: OperationType::Query,
named_type: Type::Named {
name: "Query".to_string(),
ast_ptr: None,
},
ast_ptr: None,
}
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct ObjectTypeDefinition {
pub(crate) id: Uuid,
pub(crate) description: Option<String>,
pub(crate) name: Name,
pub(crate) implements_interfaces: Arc<Vec<ImplementsInterface>>,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) fields_definition: Arc<Vec<FieldDefinition>>,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl ObjectTypeDefinition {
pub fn id(&self) -> &Uuid {
&self.id
}
pub fn name(&self) -> &str {
self.name.src()
}
pub fn name_src(&self) -> &Name {
&self.name
}
pub fn description(&self) -> Option<&str> {
self.description.as_deref()
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn fields_definition(&self) -> &[FieldDefinition] {
self.fields_definition.as_ref()
}
pub fn field(&self, name: &str) -> Option<&FieldDefinition> {
self.fields_definition().iter().find(|f| f.name() == name)
}
pub fn implements_interfaces(&self) -> &[ImplementsInterface] {
self.implements_interfaces.as_ref()
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct ImplementsInterface {
pub(crate) interface: Name,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl ImplementsInterface {
pub fn interface_definition(
&self,
db: &dyn DocumentDatabase,
) -> Option<Arc<InterfaceTypeDefinition>> {
db.find_interface_by_name(self.interface().to_string())
}
pub fn interface(&self) -> &str {
self.interface.src()
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct FieldDefinition {
pub(crate) description: Option<String>,
pub(crate) name: Name,
pub(crate) arguments: ArgumentsDefinition,
pub(crate) ty: Type,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl FieldDefinition {
pub fn name(&self) -> &str {
self.name.src()
}
pub fn description(&self) -> Option<&str> {
self.description.as_deref()
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
pub fn ty(&self) -> &Type {
&self.ty
}
pub fn arguments(&self) -> &ArgumentsDefinition {
&self.arguments
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct ArgumentsDefinition {
pub(crate) input_values: Arc<Vec<InputValueDefinition>>,
pub(crate) ast_ptr: Option<SyntaxNodePtr>,
}
impl ArgumentsDefinition {
pub fn input_values(&self) -> &[InputValueDefinition] {
self.input_values.as_ref()
}
pub fn ast_ptr(&self) -> Option<&SyntaxNodePtr> {
self.ast_ptr.as_ref()
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> Option<SyntaxNode> {
self.ast_ptr()
.map(|ptr| ptr.to_node(&rowan::SyntaxNode::new_root(db.document())))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct InputValueDefinition {
pub(crate) description: Option<String>,
pub(crate) name: Name,
pub(crate) ty: Type,
pub(crate) default_value: Option<DefaultValue>,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) ast_ptr: Option<SyntaxNodePtr>,
}
impl InputValueDefinition {
pub fn name(&self) -> &str {
self.name.src()
}
pub fn description(&self) -> Option<&str> {
self.description.as_deref()
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn ast_ptr(&self) -> Option<&SyntaxNodePtr> {
self.ast_ptr.as_ref()
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> Option<SyntaxNode> {
self.ast_ptr()
.map(|ptr| ptr.to_node(&rowan::SyntaxNode::new_root(db.document())))
}
pub fn ty(&self) -> &Type {
&self.ty
}
pub fn default_value(&self) -> Option<&DefaultValue> {
self.default_value.as_ref()
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct ScalarTypeDefinition {
pub(crate) id: Uuid,
pub(crate) description: Option<String>,
pub(crate) name: Name,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) ast_ptr: Option<SyntaxNodePtr>,
pub(crate) built_in: bool,
}
impl ScalarTypeDefinition {
pub fn id(&self) -> &Uuid {
&self.id
}
pub fn name(&self) -> &str {
self.name.src()
}
pub fn name_src(&self) -> &Name {
&self.name
}
pub fn description(&self) -> Option<&str> {
self.description.as_deref()
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn ast_ptr(&self) -> Option<&SyntaxNodePtr> {
self.ast_ptr.as_ref()
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> Option<SyntaxNode> {
self.ast_ptr()
.map(|ptr| ptr.to_node(&rowan::SyntaxNode::new_root(db.document())))
}
pub fn is_built_in(&self) -> bool {
self.built_in
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct EnumTypeDefinition {
pub(crate) id: Uuid,
pub(crate) description: Option<String>,
pub(crate) name: Name,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) enum_values_definition: Arc<Vec<EnumValueDefinition>>,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl EnumTypeDefinition {
pub fn id(&self) -> &Uuid {
&self.id
}
pub fn name(&self) -> &str {
self.name.src()
}
pub fn name_src(&self) -> &Name {
&self.name
}
pub fn description(&self) -> Option<&str> {
self.description.as_deref()
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn enum_values_definition(&self) -> &[EnumValueDefinition] {
self.enum_values_definition.as_ref()
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct EnumValueDefinition {
pub(crate) description: Option<String>,
pub(crate) enum_value: Name,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl EnumValueDefinition {
pub fn enum_value(&self) -> &str {
self.enum_value.src()
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct UnionTypeDefinition {
pub(crate) id: Uuid,
pub(crate) description: Option<String>,
pub(crate) name: Name,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) union_members: Arc<Vec<UnionMember>>,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl UnionTypeDefinition {
pub fn id(&self) -> &Uuid {
&self.id
}
pub fn name(&self) -> &str {
self.name.src()
}
pub fn name_src(&self) -> &Name {
&self.name
}
pub fn description(&self) -> Option<&str> {
self.description.as_deref()
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn union_members(&self) -> &[UnionMember] {
self.union_members.as_ref()
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct UnionMember {
pub(crate) name: Name,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl UnionMember {
pub fn name(&self) -> &str {
self.name.src()
}
pub fn object(&self, db: &dyn DocumentDatabase) -> Option<Arc<ObjectTypeDefinition>> {
db.find_object_type_by_name(self.name().to_string())
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct InterfaceTypeDefinition {
pub(crate) id: Uuid,
pub(crate) description: Option<String>,
pub(crate) name: Name,
pub(crate) implements_interfaces: Arc<Vec<ImplementsInterface>>,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) fields_definition: Arc<Vec<FieldDefinition>>,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl InterfaceTypeDefinition {
pub fn id(&self) -> &Uuid {
&self.id
}
pub fn name(&self) -> &str {
self.name.src()
}
pub fn name_src(&self) -> &Name {
&self.name
}
pub fn description(&self) -> Option<&str> {
self.description.as_deref()
}
pub fn implements_interfaces(&self) -> &[ImplementsInterface] {
self.implements_interfaces.as_ref()
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn fields_definition(&self) -> &[FieldDefinition] {
self.fields_definition.as_ref()
}
pub fn field(&self, name: &str) -> Option<&FieldDefinition> {
self.fields_definition().iter().find(|f| f.name() == name)
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct InputObjectTypeDefinition {
pub(crate) id: Uuid,
pub(crate) description: Option<String>,
pub(crate) name: Name,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) input_fields_definition: Arc<Vec<InputValueDefinition>>,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl InputObjectTypeDefinition {
pub fn id(&self) -> &Uuid {
&self.id
}
pub fn name(&self) -> &str {
self.name.src()
}
pub fn name_src(&self) -> &Name {
&self.name
}
pub fn description(&self) -> Option<&str> {
self.description.as_deref()
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn input_fields_definition(&self) -> &[InputValueDefinition] {
self.input_fields_definition.as_ref()
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct Name {
pub(crate) src: String,
pub(crate) ast_ptr: Option<SyntaxNodePtr>,
}
impl Name {
pub fn src(&self) -> &str {
self.src.as_ref()
}
pub fn ast_ptr(&self) -> Option<&SyntaxNodePtr> {
self.ast_ptr.as_ref()
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> Option<SyntaxNode> {
self.ast_ptr()
.map(|ptr| ptr.to_node(&rowan::SyntaxNode::new_root(db.document())))
}
}
impl From<Name> for String {
fn from(name: Name) -> String {
name.src().to_owned()
}
}
impl From<String> for Name {
fn from(name: String) -> Name {
Name {
src: name,
ast_ptr: None,
}
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct SchemaExtension {
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) root_operation_type_definition: Arc<Vec<RootOperationTypeDefinition>>,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl SchemaExtension {
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn root_operation_type_definition(&self) -> &[RootOperationTypeDefinition] {
self.root_operation_type_definition.as_ref()
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
self.ast_ptr
.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct ScalarTypeExtension {
pub(crate) name: Name,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl ScalarTypeExtension {
pub fn name(&self) -> &str {
self.name.src()
}
pub fn name_src(&self) -> &Name {
&self.name
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
self.ast_ptr
.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct ObjectTypeExtension {
pub(crate) name: Name,
pub(crate) implements_interfaces: Arc<Vec<ImplementsInterface>>,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) fields_definition: Arc<Vec<FieldDefinition>>,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl ObjectTypeExtension {
pub fn name(&self) -> &str {
self.name.src()
}
pub fn name_src(&self) -> &Name {
&self.name
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn fields_definition(&self) -> &[FieldDefinition] {
self.fields_definition.as_ref()
}
pub fn field(&self, name: &str) -> Option<&FieldDefinition> {
self.fields_definition().iter().find(|f| f.name() == name)
}
pub fn implements_interfaces(&self) -> &[ImplementsInterface] {
self.implements_interfaces.as_ref()
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct InterfaceTypeExtension {
pub(crate) name: Name,
pub(crate) implements_interfaces: Arc<Vec<ImplementsInterface>>,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) fields_definition: Arc<Vec<FieldDefinition>>,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl InterfaceTypeExtension {
pub fn name(&self) -> &str {
self.name.src()
}
pub fn name_src(&self) -> &Name {
&self.name
}
pub fn implements_interfaces(&self) -> &[ImplementsInterface] {
self.implements_interfaces.as_ref()
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn fields_definition(&self) -> &[FieldDefinition] {
self.fields_definition.as_ref()
}
pub fn field(&self, name: &str) -> Option<&FieldDefinition> {
self.fields_definition().iter().find(|f| f.name() == name)
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct UnionTypeExtension {
pub(crate) name: Name,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) union_members: Arc<Vec<UnionMember>>,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl UnionTypeExtension {
pub fn name(&self) -> &str {
self.name.src()
}
pub fn name_src(&self) -> &Name {
&self.name
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn union_members(&self) -> &[UnionMember] {
self.union_members.as_ref()
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct EnumTypeExtension {
pub(crate) name: Name,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) enum_values_definition: Arc<Vec<EnumValueDefinition>>,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl EnumTypeExtension {
pub fn name(&self) -> &str {
self.name.src()
}
pub fn name_src(&self) -> &Name {
&self.name
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn enum_values_definition(&self) -> &[EnumValueDefinition] {
self.enum_values_definition.as_ref()
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct InputObjectTypeExtension {
pub(crate) name: Name,
pub(crate) directives: Arc<Vec<Directive>>,
pub(crate) input_fields_definition: Arc<Vec<InputValueDefinition>>,
pub(crate) ast_ptr: SyntaxNodePtr,
}
impl InputObjectTypeExtension {
pub fn name(&self) -> &str {
self.name.src()
}
pub fn name_src(&self) -> &Name {
&self.name
}
pub fn directives(&self) -> &[Directive] {
self.directives.as_ref()
}
pub fn input_fields_definition(&self) -> &[InputValueDefinition] {
self.input_fields_definition.as_ref()
}
pub fn ast_ptr(&self) -> &SyntaxNodePtr {
&self.ast_ptr
}
pub fn ast_node(&self, db: &dyn DocumentDatabase) -> SyntaxNode {
let syntax_node_ptr = self.ast_ptr();
syntax_node_ptr.to_node(&rowan::SyntaxNode::new_root(db.document()))
}
}
#[cfg(test)]
mod tests {
use crate::ApolloCompiler;
use crate::DocumentDatabase;
#[test]
fn huge_floats() {
let compiler = ApolloCompiler::new(
"input HugeFloats {
a: Float = 9876543210
b: Float = 9876543210.0
c: Float = 98765432109876543210
d: Float = 98765432109876543210.0
}",
);
let default_values: Vec<_> = compiler
.db
.find_input_object_by_name("HugeFloats".into())
.unwrap()
.input_fields_definition
.iter()
.map(|field| {
f64::try_from(field.default_value().unwrap())
.unwrap()
.to_string()
})
.collect();
assert_eq!(default_values[0], "9876543210");
assert_eq!(default_values[1], "9876543210");
assert_eq!(default_values[2], "98765432109876540000");
assert_eq!(default_values[3], "98765432109876540000");
}
#[test]
fn syntax_errors() {
let compiler = ApolloCompiler::new(
"type Person {
id: ID!
name: String
appearedIn: [Film]s
directed: [Film]
}",
);
let person = compiler
.db
.find_object_type_by_name("Person".into())
.unwrap();
let hir_field_names: Vec<_> = person
.fields_definition
.iter()
.map(|field| field.name())
.collect();
assert_eq!(hir_field_names, ["id", "name", "appearedIn", "directed"]);
}
}