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
use core::fmt;
use std::borrow::Cow;

use crate::value::{Constant, Text};

#[derive(Debug)]
enum FieldKind<'a> {
    Required(Constant<Cow<'a, str>>),
    Optional(Constant<Cow<'a, str>>),
    Array(Constant<Cow<'a, str>>),
    RequiredUnsupported(Text<Cow<'a, str>>),
    OptionalUnsupported(Text<Cow<'a, str>>),
    ArrayUnsupported(Text<Cow<'a, str>>),
}

impl<'a> FieldKind<'a> {
    fn take_type(&mut self) -> Cow<'a, str> {
        match self {
            FieldKind::Required(Constant(s)) => std::mem::take(s),
            FieldKind::Optional(Constant(s)) => std::mem::take(s),
            FieldKind::Array(Constant(s)) => std::mem::take(s),
            FieldKind::RequiredUnsupported(Text(s)) => std::mem::take(s),
            FieldKind::OptionalUnsupported(Text(s)) => std::mem::take(s),
            FieldKind::ArrayUnsupported(Text(s)) => std::mem::take(s),
        }
    }
}

/// A type of a field in the datamodel.
#[derive(Debug)]
pub struct FieldType<'a> {
    inner: FieldKind<'a>,
}

impl<'a> FieldType<'a> {
    /// The field is required, rendered with only the name of the
    /// type. For example: `Int`.
    ///
    /// The name will be sanitized, removing unsupported characters.
    pub fn required(name: impl Into<Cow<'a, str>>) -> Self {
        let name = Constant::new_no_validate(name.into());

        Self {
            inner: FieldKind::Required(name),
        }
    }

    /// Convert the field type to optional.
    pub fn into_optional(&mut self) {
        let inner = match self.inner {
            ref mut s @ FieldKind::Required(_) => FieldKind::Optional(Constant::new_no_validate(s.take_type())),
            ref mut s @ FieldKind::Array(_) => FieldKind::Optional(Constant::new_no_validate(s.take_type())),
            ref mut s @ FieldKind::RequiredUnsupported(_) => FieldKind::OptionalUnsupported(Text(s.take_type())),
            ref mut s @ FieldKind::ArrayUnsupported(_) => FieldKind::OptionalUnsupported(Text(s.take_type())),

            FieldKind::Optional(_) => return,
            FieldKind::OptionalUnsupported(_) => return,
        };

        self.inner = inner;
    }

    /// Convert the field type to array.
    pub fn into_array(&mut self) {
        let inner = match self.inner {
            ref mut s @ FieldKind::Required(_) => FieldKind::Array(Constant::new_no_validate(s.take_type())),
            ref mut s @ FieldKind::Optional(_) => FieldKind::Array(Constant::new_no_validate(s.take_type())),
            ref mut s @ FieldKind::RequiredUnsupported(_) => FieldKind::ArrayUnsupported(Text(s.take_type())),
            ref mut s @ FieldKind::OptionalUnsupported(_) => FieldKind::ArrayUnsupported(Text(s.take_type())),

            FieldKind::Array(_) => return,
            FieldKind::ArrayUnsupported(_) => return,
        };

        self.inner = inner;
    }

    /// Set the field type to be unsupported by Prisma.
    pub fn into_unsupported(&mut self) {
        let inner = match self.inner {
            ref mut s @ FieldKind::Required(_) => FieldKind::RequiredUnsupported(Text(s.take_type())),
            ref mut s @ FieldKind::Optional(_) => FieldKind::OptionalUnsupported(Text(s.take_type())),
            ref mut s @ FieldKind::Array(_) => FieldKind::ArrayUnsupported(Text(s.take_type())),

            _ => return,
        };

        self.inner = inner;
    }
}

impl<'a> fmt::Display for FieldType<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.inner {
            FieldKind::Required(ref t) => t.fmt(f),
            FieldKind::Optional(ref t) => {
                t.fmt(f)?;
                f.write_str("?")
            }
            FieldKind::Array(ref t) => {
                t.fmt(f)?;
                f.write_str("[]")
            }
            FieldKind::RequiredUnsupported(ref t) => {
                f.write_str("Unsupported(")?;
                t.fmt(f)?;
                f.write_str(")")
            }
            FieldKind::OptionalUnsupported(ref t) => {
                f.write_str("Unsupported(")?;
                t.fmt(f)?;
                f.write_str(")?")
            }
            FieldKind::ArrayUnsupported(ref t) => {
                f.write_str("Unsupported(")?;
                t.fmt(f)?;
                f.write_str(")[]")
            }
        }
    }
}