1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
use super::{
Attribute, Comment, Identifier, Span, WithAttributes, WithDocumentation, WithIdentifier, WithName, WithSpan,
};
/// A field definition in a model or a composite type.
#[derive(Debug, Clone)]
pub struct Field {
/// The field's type.
///
/// ```ignore
/// name String
/// ^^^^^^
/// ```
pub field_type: FieldType,
/// The name of the field.
///
/// ```ignore
/// name String
/// ^^^^
/// ```
pub(crate) name: Identifier,
/// The arity of the field.
pub arity: FieldArity,
/// The attributes of this field.
///
/// ```ignore
/// name String @id @default("lol")
/// ^^^^^^^^^^^^^^^^^^^
/// ```
pub attributes: Vec<Attribute>,
/// The comments for this field.
///
/// ```ignore
/// /// Lorem ipsum
/// ^^^^^^^^^^^
/// name String @id @default("lol")
/// ```
pub(crate) documentation: Option<Comment>,
/// The location of this field in the text representation.
pub(crate) span: Span,
}
impl Field {
/// Finds the position span of the argument in the given field attribute.
pub fn span_for_argument(&self, attribute: &str, argument: &str) -> Option<Span> {
self.attributes
.iter()
.filter(|a| a.name() == attribute)
.flat_map(|a| a.arguments.iter())
.filter(|a| a.name.as_ref().map(|n| n.name.as_str()) == Some(argument))
.map(|a| a.span)
.next()
}
/// Finds the position span of the given attribute.
pub fn span_for_attribute(&self, attribute: &str) -> Option<Span> {
self.attributes
.iter()
.filter(|a| a.name() == attribute)
.map(|a| a.span)
.next()
}
/// The name of the field
pub fn name(&self) -> &str {
&self.name.name
}
}
impl WithIdentifier for Field {
fn identifier(&self) -> &Identifier {
&self.name
}
}
impl WithSpan for Field {
fn span(&self) -> Span {
self.span
}
}
impl WithAttributes for Field {
fn attributes(&self) -> &[Attribute] {
&self.attributes
}
}
impl WithDocumentation for Field {
fn documentation(&self) -> Option<&str> {
self.documentation.as_ref().map(|doc| doc.text.as_str())
}
}
/// An arity of a data model field.
#[derive(Copy, Debug, Clone, PartialEq, Eq, Hash)]
pub enum FieldArity {
/// The field either must be in an insert statement, or the field must have
/// a default value for the insert to succeed.
///
/// ```ignore
/// name String
/// ```
Required,
/// The field does not need to be in an insert statement for the write to
/// succeed.
///
/// ```ignore
/// name String?
/// ```
Optional,
/// The field can have multiple values stored in the same column.
///
/// ```ignore
/// name String[]
/// ```
List,
}
impl FieldArity {
pub fn is_list(&self) -> bool {
matches!(self, &FieldArity::List)
}
pub fn is_optional(&self) -> bool {
matches!(self, &FieldArity::Optional)
}
pub fn is_required(&self) -> bool {
matches!(self, &FieldArity::Required)
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum FieldType {
Supported(Identifier),
/// Unsupported("...")
Unsupported(String, Span),
}
impl FieldType {
pub fn span(&self) -> Span {
match self {
FieldType::Supported(ident) => ident.span,
FieldType::Unsupported(_, span) => *span,
}
}
pub fn as_unsupported(&self) -> Option<(&str, &Span)> {
match self {
FieldType::Unsupported(name, span) => Some((name, span)),
FieldType::Supported(_) => None,
}
}
}