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
use super::{CompositeTypeFieldWalker, ModelWalker, RelationFieldWalker, ScalarFieldWalker, Walker};
use crate::{
    types::{RelationField, ScalarField},
    ScalarType,
};
use schema_ast::ast;

/// A model field, scalar or relation.
pub type FieldWalker<'db> = Walker<'db, (ast::ModelId, ast::FieldId)>;

impl<'db> FieldWalker<'db> {
    /// The AST node for the field.
    pub fn ast_field(self) -> &'db ast::Field {
        &self.db.ast[self.id.0][self.id.1]
    }

    /// The field name.
    pub fn name(self) -> &'db str {
        self.ast_field().name()
    }

    /// Traverse the field's parent model.
    pub fn model(self) -> ModelWalker<'db> {
        self.walk(self.id.0)
    }

    /// Find out which kind of field this is.
    pub fn refine(self) -> RefinedFieldWalker<'db> {
        match self.db.types.refine_field(self.id) {
            either::Either::Left(id) => RefinedFieldWalker::Relation(self.walk(id)),
            either::Either::Right(id) => RefinedFieldWalker::Scalar(self.walk(id)),
        }
    }
}

/// A field that has been identified as scalar field or relation field.
#[derive(Copy, Clone)]
pub enum RefinedFieldWalker<'db> {
    /// A scalar field
    Scalar(ScalarFieldWalker<'db>),
    /// A relation field
    Relation(RelationFieldWalker<'db>),
}

impl<'db> From<ScalarFieldWalker<'db>> for FieldWalker<'db> {
    fn from(w: ScalarFieldWalker<'db>) -> Self {
        let ScalarField { model_id, field_id, .. } = w.db.types[w.id];
        Walker {
            db: w.db,
            id: (model_id, field_id),
        }
    }
}

impl<'db> From<RelationFieldWalker<'db>> for FieldWalker<'db> {
    fn from(w: RelationFieldWalker<'db>) -> Self {
        let RelationField { model_id, field_id, .. } = w.db.types[w.id];
        Walker {
            db: w.db,
            id: (model_id, field_id),
        }
    }
}

#[derive(Copy, Clone)]
enum InnerTypedFieldWalker<'db> {
    Scalar(ScalarFieldWalker<'db>),
    Composite(CompositeTypeFieldWalker<'db>),
}

impl<'db> From<ScalarFieldWalker<'db>> for TypedFieldWalker<'db> {
    fn from(w: ScalarFieldWalker<'db>) -> Self {
        Self {
            inner: InnerTypedFieldWalker::Scalar(w),
        }
    }
}

impl<'db> From<CompositeTypeFieldWalker<'db>> for TypedFieldWalker<'db> {
    fn from(w: CompositeTypeFieldWalker<'db>) -> Self {
        Self {
            inner: InnerTypedFieldWalker::Composite(w),
        }
    }
}

/// A model or composite type field of a scalar type.
#[derive(Clone, Copy)]
pub struct TypedFieldWalker<'db> {
    inner: InnerTypedFieldWalker<'db>,
}

impl<'db> TypedFieldWalker<'db> {
    /// The type of the field in case it is a scalar type (not an enum, not a composite type).
    pub fn scalar_type(self) -> Option<ScalarType> {
        match self.inner {
            InnerTypedFieldWalker::Scalar(field) => field.scalar_type(),
            InnerTypedFieldWalker::Composite(field) => field.scalar_type(),
        }
    }

    /// (attribute scope, native type name, arguments, span)
    ///
    /// For example: `@db.Text` would translate to ("db", "Text", &[], <the span>)
    pub fn raw_native_type(self) -> Option<(&'db str, &'db str, &'db [String], ast::Span)> {
        match self.inner {
            InnerTypedFieldWalker::Scalar(sf) => sf.raw_native_type(),
            InnerTypedFieldWalker::Composite(cf) => cf.raw_native_type(),
        }
    }
}