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
//! Some common lints whose code can be shared between rorm-macro and rorm-cli.

use crate::imr::Annotation;

/// Simple struct storing whether a specific annotation is set on a given field or not.
#[derive(Copy, Clone, Default, Debug)]
pub struct Annotations {
    /// Does the field have the [Annotation::AutoCreateTime]?
    pub auto_create_time: bool,

    /// Does the field have the [Annotation::AutoUpdateTime]?
    pub auto_update_time: bool,

    /// Does the field have the [Annotation::AutoIncrement]?
    pub auto_increment: bool,

    /// Does the field have the [Annotation::Choices]?
    pub choices: bool,

    /// Does the field have the [Annotation::DefaultValue]?
    pub default: bool,

    /// Does the field have the [Annotation::Index]?
    pub index: bool,

    /// Does the field have the [Annotation::MaxLength]?
    pub max_length: bool,

    /// Does the field have the [Annotation::NotNull]?
    pub not_null: bool,

    /// Does the field have the [Annotation::PrimaryKey]?
    pub primary_key: bool,

    /// Does the field have the [Annotation::Unique]?
    pub unique: bool,

    /// Does the field have the [Annotation::ForeignKey]?
    pub foreign_key: bool,
}

impl Annotations {
    /// Check whether this set of annotations is valid.
    ///
    /// Returns a non-empty error message, when it is not.
    // Disable auto-format to make the following match compacter and more readable.
    #[rustfmt::skip]
    pub const fn check(self) -> Result<(), &'static str> {
        // Alias to reduce line length and noise
        use Annotations as A;

        let msg = match self {
            A { auto_create_time: true, auto_increment: true, .. } => "AutoCreateTime and AutoIncrement are mutually exclusive",
            A { auto_create_time: true, choices: true, .. } => "AutoCreateTime and Choices are mutually exclusive",
            A { auto_create_time: true, default: true, .. } => "AutoCreateTime and DefaultValue are mutually exclusive",
            A { auto_create_time: true, max_length: true, .. } => "AutoCreateTime and MaxLength are mutually exclusive",
            A { auto_create_time: true, primary_key: true, .. } => "AutoCreateTime and PrimaryKey are mutually exclusive",
            A { auto_create_time: true, unique: true, .. } => "AutoCreateTime and Unique are mutually exclusive",
            A { auto_update_time: true, auto_increment: true, .. } => "AutoUpdateTime and AutoIncrement are mutually exclusive",
            A { auto_update_time: true, choices: true, .. } => "AutoUpdateTime and Choices are mutually exclusive",
            A { auto_update_time: true, max_length: true, .. } => "AutoUpdateTime and MaxLength are mutually exclusive",
            A { auto_update_time: true, primary_key: true, .. } => "AutoUpdateTime and PrimaryKey are mutually exclusive",
            A { auto_update_time: true, unique: true, .. } => "AutoUpdateTime and Unique are mutually exclusive",
            A { auto_increment: true, choices: true, .. } => "AutoIncrement and Choices are mutually exclusive",
            A { auto_increment: true, max_length: true, .. } => "AutoIncrement and MaxLength are mutually exclusive",
            A { choices: true, max_length: true, .. } => "Choices and MaxLength are mutually exclusive",
            A { choices: true, primary_key: true, .. } => "Choices and PrimaryKey are mutually exclusive",
            A { choices: true, unique: true, .. } => "Choices and Unique are mutually exclusive",
            A { default: true, auto_update_time: true, .. } => "DefaultValue and AutoUpdateTime are mutually exclusive",
            A { default: true, auto_increment: true, .. } => "DefaultValue and AutoIncrement are mutually exclusive",
            A { default: true, primary_key: true, .. } => "DefaultValue and PrimaryKey are mutually exclusive",
            A { default: true, unique: true, .. } => "DefaultValue and Unique are mutually exclusive",
            A { index: true, primary_key: true, .. } => "Index and PrimaryKey are mutually exclusive",
            A { not_null: true, primary_key: true, .. } => "NotNull and PrimaryKey are mutually exclusive",

            A { auto_increment: true, primary_key: false, .. } => "AutoIncrement requires PrimaryKey",

            A { auto_update_time: true, not_null: true, auto_create_time: false, default: false, ..} => "AutoUpdateTime in combination with NotNull requires ether DefaultValue or AutoCreateTime",

            _ => "",
        };

        // Create Result based on error message length to avoid using Err() in the match expression.
        if !msg.is_empty() {
            Err(msg)
        } else {
            Ok(())
        }
    }
}

impl From<&[Annotation]> for Annotations {
    fn from(annotations: &[Annotation]) -> Self {
        let mut result = Annotations::default();
        for annotation in annotations {
            match annotation {
                Annotation::AutoCreateTime => result.auto_create_time = true,
                Annotation::AutoUpdateTime => result.auto_update_time = true,
                Annotation::AutoIncrement => result.auto_increment = true,
                Annotation::Choices(_) => result.choices = true,
                Annotation::DefaultValue(_) => result.default = true,
                Annotation::Index(_) => result.index = true,
                Annotation::MaxLength(_) => result.max_length = true,
                Annotation::NotNull => result.not_null = true,
                Annotation::PrimaryKey => result.primary_key = true,
                Annotation::Unique => result.unique = true,
                Annotation::ForeignKey(_) => result.foreign_key = true,
            }
        }
        result
    }
}