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
use super::errors::SQLiteSourceError;
use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
use fehler::{throw, throws};
use rusqlite::types::Type;
use std::convert::TryFrom;

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum SQLiteTypeSystem {
    Bool(bool),
    Int8(bool),
    Int4(bool),
    Int2(bool),
    Real(bool),
    Text(bool),
    Date(bool),
    Time(bool),
    Timestamp(bool),
    Blob(bool),
}

impl_typesystem! {
    system = SQLiteTypeSystem,
    mappings = {
        { Bool => bool }
        { Int8 => i64 }
        { Int4 => i32 }
        { Int2 => i16 }
        { Real => f64 }
        { Text => Box<str> }
        { Date => NaiveDate}
        { Time => NaiveTime}
        { Timestamp => NaiveDateTime}
        { Blob => Vec<u8>}
    }
}

impl TryFrom<Type> for SQLiteTypeSystem {
    type Error = SQLiteSourceError;

    #[throws(SQLiteSourceError)]
    fn try_from(ty: Type) -> Self {
        use SQLiteTypeSystem::*;
        match ty {
            Type::Integer => Int8(true),
            Type::Real => Real(true),
            Type::Text => Text(true),
            Type::Blob => Blob(true),
            Type::Null => throw!(SQLiteSourceError::InferTypeFromNull),
        }
    }
}

impl TryFrom<(Option<&str>, Type)> for SQLiteTypeSystem {
    type Error = SQLiteSourceError;

    #[throws(SQLiteSourceError)]
    fn try_from(types: (Option<&str>, Type)) -> Self {
        use SQLiteTypeSystem::*;
        match types {
            // derive from column's declare type, some rules refer to:
            // https://www.sqlite.org/datatype3.html#affname
            (Some(decl_type), ty) => {
                let decl_type = decl_type.to_lowercase();
                match decl_type.as_str() {
                    "int4" => Int4(true),
                    "int2" => Int2(true),
                    "boolean" | "bool" => Bool(true),
                    "date" => Date(true),
                    "time" => Time(true),
                    "datetime" | "timestamp" => Timestamp(true),
                    _ if decl_type.contains("int") => Int8(true),
                    _ if decl_type.contains("char")
                        || decl_type.contains("clob")
                        || decl_type.contains("text") =>
                    {
                        Text(true)
                    }
                    _ if decl_type.contains("real")
                        || decl_type.contains("floa")
                        || decl_type.contains("doub") =>
                    {
                        Real(true)
                    }
                    _ if decl_type.contains("blob") => Blob(true),
                    _ => SQLiteTypeSystem::try_from(ty)?,
                }
            }
            // derive from value type directly if no declare type available
            (None, ty) => SQLiteTypeSystem::try_from(ty)?,
        }
    }
}