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
use super::{ArgumentsList, Identifier, Span, WithIdentifier, WithSpan};
use std::ops::Index;

/// An attribute (following `@` or `@@``) on a model, model field, enum, enum value or composite
/// type field.
#[derive(Debug, Clone)]
pub struct Attribute {
    /// The name of the attribute:
    ///
    /// ```ignore
    /// @@index([a, b, c])
    ///   ^^^^^
    /// ```
    pub name: Identifier,
    /// The arguments of the attribute.
    ///
    /// ```ignore
    /// @@index([a, b, c], map: "myidix")
    ///         ^^^^^^^^^^^^^^^^^^^^^^^^
    /// ```
    pub arguments: ArgumentsList,
    /// The AST span of the node.
    pub span: Span,
}

impl Attribute {
    /// Try to find the argument and return its span.
    pub fn span_for_argument(&self, argument: &str) -> Option<Span> {
        self.arguments
            .iter()
            .find(|a| a.name.as_ref().map(|n| n.name.as_str()) == Some(argument))
            .map(|a| a.span)
    }
}

impl WithIdentifier for Attribute {
    fn identifier(&self) -> &Identifier {
        &self.name
    }
}

impl WithSpan for Attribute {
    fn span(&self) -> Span {
        self.span
    }
}

/// A node containing attributes.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum AttributeContainer {
    Model(super::ModelId),
    ModelField(super::ModelId, super::FieldId),
    Enum(super::EnumId),
    EnumValue(super::EnumId, u32),
    CompositeTypeField(super::CompositeTypeId, super::FieldId),
}

impl From<super::ModelId> for AttributeContainer {
    fn from(v: super::ModelId) -> Self {
        Self::Model(v)
    }
}

impl From<(super::ModelId, super::FieldId)> for AttributeContainer {
    fn from((model, field): (super::ModelId, super::FieldId)) -> Self {
        Self::ModelField(model, field)
    }
}

impl From<super::EnumId> for AttributeContainer {
    fn from(v: super::EnumId) -> Self {
        Self::Enum(v)
    }
}

impl From<(super::CompositeTypeId, super::FieldId)> for AttributeContainer {
    fn from((ct, field): (super::CompositeTypeId, super::FieldId)) -> Self {
        Self::CompositeTypeField(ct, field)
    }
}

impl From<(super::EnumId, u32)> for AttributeContainer {
    fn from((enm, val): (super::EnumId, u32)) -> Self {
        Self::EnumValue(enm, val)
    }
}

/// An attribute (@ or @@) node in the AST.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct AttributeId(AttributeContainer, u32);

impl AttributeId {
    pub fn new_in_container(container: AttributeContainer, idx: usize) -> AttributeId {
        AttributeId(container, idx as u32)
    }
}

impl Index<AttributeContainer> for super::SchemaAst {
    type Output = [Attribute];

    fn index(&self, index: AttributeContainer) -> &Self::Output {
        match index {
            AttributeContainer::Model(model_id) => &self[model_id].attributes,
            AttributeContainer::ModelField(model_id, field_id) => &self[model_id][field_id].attributes,
            AttributeContainer::Enum(enum_id) => &self[enum_id].attributes,
            AttributeContainer::EnumValue(enum_id, value_idx) => &self[enum_id].values[value_idx as usize].attributes,
            AttributeContainer::CompositeTypeField(ctid, field_id) => &self[ctid][field_id].attributes,
        }
    }
}

impl Index<AttributeId> for super::SchemaAst {
    type Output = Attribute;

    fn index(&self, index: AttributeId) -> &Self::Output {
        &self[index.0][index.1 as usize]
    }
}