tursotui_sql/
validation.rs1pub fn sanitize_pragma_value(name: &str, value: &str) -> Result<String, String> {
12 match name {
13 "cache_size" | "busy_timeout" => {
15 let n: i64 = value
16 .trim()
17 .parse()
18 .map_err(|_| format!("{name} must be an integer"))?;
19 Ok(n.to_string())
20 }
21 "max_page_count" => {
23 let n: i64 = value
24 .trim()
25 .parse()
26 .map_err(|_| "max_page_count must be a positive integer".to_string())?;
27 if n > 0 {
28 Ok(n.to_string())
29 } else {
30 Err("max_page_count must be a positive integer".to_string())
31 }
32 }
33 "foreign_keys" | "query_only" => match value.trim() {
35 "0" | "1" => Ok(value.trim().to_string()),
36 _ => Err(format!("{name} must be 0 or 1")),
37 },
38 "synchronous" => match value.trim() {
41 "0" | "2" => Ok(value.trim().to_string()),
42 _ => Err("synchronous must be 0 (OFF) or 2 (FULL) on Turso".to_string()),
43 },
44 "temp_store" => match value.trim() {
45 "0" | "1" | "2" => Ok(value.trim().to_string()),
46 _ => Err("temp_store must be 0-2".to_string()),
47 },
48 _ => Err(format!("{name} is not writable")),
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 #[test]
57 fn cache_size_valid_positive() {
58 assert_eq!(sanitize_pragma_value("cache_size", "2000").unwrap(), "2000");
59 }
60
61 #[test]
62 fn cache_size_valid_negative() {
63 assert_eq!(
64 sanitize_pragma_value("cache_size", "-4096").unwrap(),
65 "-4096"
66 );
67 }
68
69 #[test]
70 fn cache_size_trims_whitespace() {
71 assert_eq!(
72 sanitize_pragma_value("cache_size", " 100 ").unwrap(),
73 "100"
74 );
75 }
76
77 #[test]
78 fn cache_size_rejects_non_integer() {
79 assert!(sanitize_pragma_value("cache_size", "abc").is_err());
80 }
81
82 #[test]
83 fn busy_timeout_valid() {
84 assert_eq!(
85 sanitize_pragma_value("busy_timeout", "5000").unwrap(),
86 "5000"
87 );
88 }
89
90 #[test]
91 fn busy_timeout_rejects_float() {
92 assert!(sanitize_pragma_value("busy_timeout", "1.5").is_err());
93 }
94
95 #[test]
96 fn max_page_count_valid() {
97 assert_eq!(
98 sanitize_pragma_value("max_page_count", "1073741823").unwrap(),
99 "1073741823"
100 );
101 }
102
103 #[test]
104 fn max_page_count_rejects_zero() {
105 assert!(sanitize_pragma_value("max_page_count", "0").is_err());
106 }
107
108 #[test]
109 fn max_page_count_rejects_negative() {
110 assert!(sanitize_pragma_value("max_page_count", "-1").is_err());
111 }
112
113 #[test]
114 fn foreign_keys_accepts_zero_and_one() {
115 assert_eq!(sanitize_pragma_value("foreign_keys", "0").unwrap(), "0");
116 assert_eq!(sanitize_pragma_value("foreign_keys", "1").unwrap(), "1");
117 }
118
119 #[test]
120 fn foreign_keys_rejects_other() {
121 assert!(sanitize_pragma_value("foreign_keys", "2").is_err());
122 assert!(sanitize_pragma_value("foreign_keys", "on").is_err());
123 }
124
125 #[test]
126 fn query_only_accepts_zero_and_one() {
127 assert_eq!(sanitize_pragma_value("query_only", "0").unwrap(), "0");
128 assert_eq!(sanitize_pragma_value("query_only", "1").unwrap(), "1");
129 }
130
131 #[test]
132 fn synchronous_accepts_off_and_full() {
133 assert_eq!(sanitize_pragma_value("synchronous", "0").unwrap(), "0");
134 assert_eq!(sanitize_pragma_value("synchronous", "2").unwrap(), "2");
135 }
136
137 #[test]
138 fn synchronous_rejects_normal() {
139 assert!(sanitize_pragma_value("synchronous", "1").is_err());
140 }
141
142 #[test]
143 fn temp_store_accepts_valid_range() {
144 assert_eq!(sanitize_pragma_value("temp_store", "0").unwrap(), "0");
145 assert_eq!(sanitize_pragma_value("temp_store", "1").unwrap(), "1");
146 assert_eq!(sanitize_pragma_value("temp_store", "2").unwrap(), "2");
147 }
148
149 #[test]
150 fn temp_store_rejects_out_of_range() {
151 assert!(sanitize_pragma_value("temp_store", "3").is_err());
152 }
153
154 #[test]
155 fn unknown_pragma_rejected() {
156 assert!(sanitize_pragma_value("page_size", "4096").is_err());
157 }
158}