drizzle_types/sqlite/sql_type.rs
1//! SQLite column type definitions
2//!
3//! Defines the core SQLite storage classes and type affinities.
4
5/// Enum representing supported SQLite column types.
6///
7/// These correspond to the [SQLite storage classes](https://sqlite.org/datatype3.html#storage_classes_and_datatypes).
8/// Each type maps to specific Rust types and has different capabilities for constraints and features.
9///
10/// # Examples
11///
12/// ```
13/// use drizzle_types::sqlite::SQLiteType;
14///
15/// let int_type = SQLiteType::Integer;
16/// assert_eq!(int_type.to_sql_type(), "INTEGER");
17/// assert!(int_type.is_valid_flag("autoincrement"));
18///
19/// let text_type = SQLiteType::Text;
20/// assert!(text_type.is_valid_flag("json"));
21/// assert!(!text_type.is_valid_flag("autoincrement"));
22/// ```
23#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25#[cfg_attr(feature = "serde", serde(rename_all = "UPPERCASE"))]
26pub enum SQLiteType {
27 /// SQLite INTEGER type - stores signed integers up to 8 bytes.
28 ///
29 /// See: <https://sqlite.org/datatype3.html#integer_datatype>
30 ///
31 /// Supports: primary keys, autoincrement, enums (discriminant storage)
32 Integer,
33
34 /// SQLite TEXT type - stores text in UTF-8, UTF-16BE, or UTF-16LE encoding.
35 ///
36 /// See: <https://sqlite.org/datatype3.html#text_datatype>
37 ///
38 /// Supports: enums (variant name storage), JSON serialization
39 Text,
40
41 /// SQLite BLOB type - stores binary data exactly as input.
42 ///
43 /// See: <https://sqlite.org/datatype3.html#blob_datatype>
44 ///
45 /// Supports: JSON serialization, UUID storage
46 Blob,
47
48 /// SQLite REAL type - stores floating point values as 8-byte IEEE floating point numbers.
49 ///
50 /// See: <https://sqlite.org/datatype3.html#real_datatype>
51 Real,
52
53 /// SQLite NUMERIC type - stores values as INTEGER, REAL, or TEXT depending on the value.
54 ///
55 /// See: <https://sqlite.org/datatype3.html#numeric_datatype>
56 Numeric,
57
58 /// SQLite ANY type - no type affinity, can store any type of data.
59 ///
60 /// See: <https://sqlite.org/datatype3.html#type_affinity>
61 #[default]
62 Any,
63}
64
65impl SQLiteType {
66 /// Convert from attribute name to enum variant
67 ///
68 /// Handles common attribute names used in the macro system.
69 #[must_use]
70 pub fn from_attribute_name(name: &str) -> Option<Self> {
71 if name.eq_ignore_ascii_case("integer") {
72 Some(Self::Integer)
73 } else if name.eq_ignore_ascii_case("text") {
74 Some(Self::Text)
75 } else if name.eq_ignore_ascii_case("blob") {
76 Some(Self::Blob)
77 } else if name.eq_ignore_ascii_case("real") {
78 Some(Self::Real)
79 } else if name.eq_ignore_ascii_case("number") || name.eq_ignore_ascii_case("numeric") {
80 Some(Self::Numeric)
81 } else if name.eq_ignore_ascii_case("boolean") {
82 Some(Self::Integer) // Store booleans as integers (0/1)
83 } else if name.eq_ignore_ascii_case("any") {
84 Some(Self::Any)
85 } else {
86 None
87 }
88 }
89
90 /// Get the SQL type string for this type
91 #[must_use]
92 pub const fn to_sql_type(&self) -> &'static str {
93 match self {
94 Self::Integer => "INTEGER",
95 Self::Text => "TEXT",
96 Self::Blob => "BLOB",
97 Self::Real => "REAL",
98 Self::Numeric => "NUMERIC",
99 Self::Any => "ANY",
100 }
101 }
102
103 /// Check if a flag is valid for this column type
104 ///
105 /// # Valid Flags per Type
106 ///
107 /// - `INTEGER`: `primary`, `primary_key`, `unique`, `autoincrement`, `enum`
108 /// - `TEXT`: `primary`, `primary_key`, `unique`, `json`, `enum`
109 /// - `BLOB`: `primary`, `primary_key`, `unique`, `json`
110 /// - `REAL`: `primary`, `primary_key`, `unique`
111 /// - `NUMERIC`: `primary`, `primary_key`, `unique`
112 /// - `ANY`: `primary`, `primary_key`, `unique`
113 #[must_use]
114 pub fn is_valid_flag(&self, flag: &str) -> bool {
115 matches!(flag, "primary" | "primary_key" | "unique")
116 || matches!(
117 (self, flag),
118 (Self::Integer, "autoincrement")
119 | (Self::Text | Self::Blob, "json")
120 | (Self::Text | Self::Integer, "enum")
121 )
122 }
123}
124
125impl core::fmt::Display for SQLiteType {
126 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
127 f.write_str(self.to_sql_type())
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn test_from_attribute_name() {
137 assert_eq!(
138 SQLiteType::from_attribute_name("integer"),
139 Some(SQLiteType::Integer)
140 );
141 assert_eq!(
142 SQLiteType::from_attribute_name("INTEGER"),
143 Some(SQLiteType::Integer)
144 );
145 assert_eq!(
146 SQLiteType::from_attribute_name("text"),
147 Some(SQLiteType::Text)
148 );
149 assert_eq!(
150 SQLiteType::from_attribute_name("blob"),
151 Some(SQLiteType::Blob)
152 );
153 assert_eq!(
154 SQLiteType::from_attribute_name("boolean"),
155 Some(SQLiteType::Integer)
156 );
157 assert_eq!(SQLiteType::from_attribute_name("unknown"), None);
158 }
159
160 #[test]
161 fn test_to_sql_type() {
162 assert_eq!(SQLiteType::Integer.to_sql_type(), "INTEGER");
163 assert_eq!(SQLiteType::Text.to_sql_type(), "TEXT");
164 assert_eq!(SQLiteType::Blob.to_sql_type(), "BLOB");
165 assert_eq!(SQLiteType::Real.to_sql_type(), "REAL");
166 assert_eq!(SQLiteType::Numeric.to_sql_type(), "NUMERIC");
167 assert_eq!(SQLiteType::Any.to_sql_type(), "ANY");
168 }
169
170 #[test]
171 fn test_is_valid_flag() {
172 // Autoincrement only valid for INTEGER
173 assert!(SQLiteType::Integer.is_valid_flag("autoincrement"));
174 assert!(!SQLiteType::Text.is_valid_flag("autoincrement"));
175 assert!(!SQLiteType::Blob.is_valid_flag("autoincrement"));
176
177 // JSON valid for TEXT and BLOB
178 assert!(SQLiteType::Text.is_valid_flag("json"));
179 assert!(SQLiteType::Blob.is_valid_flag("json"));
180 assert!(!SQLiteType::Integer.is_valid_flag("json"));
181
182 // Enum valid for TEXT and INTEGER
183 assert!(SQLiteType::Text.is_valid_flag("enum"));
184 assert!(SQLiteType::Integer.is_valid_flag("enum"));
185 assert!(!SQLiteType::Blob.is_valid_flag("enum"));
186
187 // Primary/unique valid for all
188 assert!(SQLiteType::Integer.is_valid_flag("primary"));
189 assert!(SQLiteType::Text.is_valid_flag("unique"));
190 assert!(SQLiteType::Blob.is_valid_flag("primary_key"));
191 }
192}