1use crate::{ColumnType, Error, Result, Value};
7
8pub trait ToValue {
10 fn to_value(&self) -> Value;
12
13 fn column_type() -> ColumnType;
15}
16
17pub trait FromValue: Sized {
19 fn from_value(value: &Value) -> Result<Self>;
21}
22
23pub trait ToRow {
25 fn to_values(&self) -> Vec<Value>;
27
28 fn column_names() -> &'static [&'static str];
30}
31
32pub trait FromRow: Sized {
34 fn from_values(values: &[Value]) -> Result<Self>;
36}
37
38pub trait TableSchema {
40 fn table_name() -> &'static str;
42
43 fn columns() -> Vec<ColumnDef>;
45
46 fn primary_key() -> &'static [&'static str];
48}
49
50#[derive(Debug, Clone)]
52pub struct ColumnDef {
53 pub name: &'static str,
55 pub column_type: ColumnType,
57 pub primary_key: bool,
59 pub not_null: bool,
61 pub unique: bool,
63 pub default: Option<Value>,
65}
66
67impl ToValue for bool {
70 fn to_value(&self) -> Value {
71 Value::Boolean(*self)
72 }
73
74 fn column_type() -> ColumnType {
75 ColumnType::Boolean
76 }
77}
78
79impl ToValue for i32 {
80 fn to_value(&self) -> Value {
81 Value::Integer(*self as i64)
82 }
83
84 fn column_type() -> ColumnType {
85 ColumnType::Integer
86 }
87}
88
89impl ToValue for i64 {
90 fn to_value(&self) -> Value {
91 Value::Integer(*self)
92 }
93
94 fn column_type() -> ColumnType {
95 ColumnType::Integer
96 }
97}
98
99impl ToValue for f64 {
100 fn to_value(&self) -> Value {
101 Value::Real(*self)
102 }
103
104 fn column_type() -> ColumnType {
105 ColumnType::Real
106 }
107}
108
109impl ToValue for String {
110 fn to_value(&self) -> Value {
111 Value::Text(self.clone())
112 }
113
114 fn column_type() -> ColumnType {
115 ColumnType::Text { max_len: None }
116 }
117}
118
119impl ToValue for &str {
120 fn to_value(&self) -> Value {
121 Value::Text(self.to_string())
122 }
123
124 fn column_type() -> ColumnType {
125 ColumnType::Text { max_len: None }
126 }
127}
128
129impl ToValue for Vec<u8> {
130 fn to_value(&self) -> Value {
131 Value::Blob(self.clone())
132 }
133
134 fn column_type() -> ColumnType {
135 ColumnType::Blob { max_len: None }
136 }
137}
138
139impl<T: ToValue> ToValue for Option<T> {
140 fn to_value(&self) -> Value {
141 match self {
142 Some(v) => v.to_value(),
143 None => Value::Null,
144 }
145 }
146
147 fn column_type() -> ColumnType {
148 T::column_type()
149 }
150}
151
152impl FromValue for bool {
155 fn from_value(value: &Value) -> Result<Self> {
156 match value {
157 Value::Boolean(b) => Ok(*b),
158 Value::Integer(i) => Ok(*i != 0),
159 Value::Null => Err(Error::TypeError {
160 expected: "BOOLEAN".to_string(),
161 actual: "NULL".to_string(),
162 }),
163 _ => Err(Error::TypeError {
164 expected: "BOOLEAN".to_string(),
165 actual: format!("{:?}", value),
166 }),
167 }
168 }
169}
170
171impl FromValue for i32 {
172 fn from_value(value: &Value) -> Result<Self> {
173 match value {
174 Value::Integer(i) => Ok(*i as i32),
175 Value::Real(r) => Ok(*r as i32),
176 Value::Null => Err(Error::TypeError {
177 expected: "INTEGER".to_string(),
178 actual: "NULL".to_string(),
179 }),
180 _ => Err(Error::TypeError {
181 expected: "INTEGER".to_string(),
182 actual: format!("{:?}", value),
183 }),
184 }
185 }
186}
187
188impl FromValue for i64 {
189 fn from_value(value: &Value) -> Result<Self> {
190 match value {
191 Value::Integer(i) => Ok(*i),
192 Value::Real(r) => Ok(*r as i64),
193 Value::Null => Err(Error::TypeError {
194 expected: "INTEGER".to_string(),
195 actual: "NULL".to_string(),
196 }),
197 _ => Err(Error::TypeError {
198 expected: "INTEGER".to_string(),
199 actual: format!("{:?}", value),
200 }),
201 }
202 }
203}
204
205impl FromValue for f64 {
206 fn from_value(value: &Value) -> Result<Self> {
207 match value {
208 Value::Real(r) => Ok(*r),
209 Value::Integer(i) => Ok(*i as f64),
210 Value::Null => Err(Error::TypeError {
211 expected: "REAL".to_string(),
212 actual: "NULL".to_string(),
213 }),
214 _ => Err(Error::TypeError {
215 expected: "REAL".to_string(),
216 actual: format!("{:?}", value),
217 }),
218 }
219 }
220}
221
222impl FromValue for String {
223 fn from_value(value: &Value) -> Result<Self> {
224 match value {
225 Value::Text(s) => Ok(s.clone()),
226 Value::Null => Err(Error::TypeError {
227 expected: "TEXT".to_string(),
228 actual: "NULL".to_string(),
229 }),
230 _ => Err(Error::TypeError {
231 expected: "TEXT".to_string(),
232 actual: format!("{:?}", value),
233 }),
234 }
235 }
236}
237
238impl FromValue for Vec<u8> {
239 fn from_value(value: &Value) -> Result<Self> {
240 match value {
241 Value::Blob(b) => Ok(b.clone()),
242 Value::Null => Err(Error::TypeError {
243 expected: "BLOB".to_string(),
244 actual: "NULL".to_string(),
245 }),
246 _ => Err(Error::TypeError {
247 expected: "BLOB".to_string(),
248 actual: format!("{:?}", value),
249 }),
250 }
251 }
252}
253
254impl<T: FromValue> FromValue for Option<T> {
255 fn from_value(value: &Value) -> Result<Self> {
256 if value.is_null() {
257 Ok(None)
258 } else {
259 T::from_value(value).map(Some)
260 }
261 }
262}
263
264#[cfg(test)]
265mod tests {
266 use super::*;
267
268 #[test]
269 fn test_to_value() {
270 assert_eq!(42i64.to_value(), Value::Integer(42));
271 assert_eq!("hello".to_value(), Value::Text("hello".to_string()));
272 assert_eq!(Some(42i64).to_value(), Value::Integer(42));
273 assert_eq!(None::<i64>.to_value(), Value::Null);
274 }
275
276 #[test]
277 fn test_from_value() {
278 assert_eq!(i64::from_value(&Value::Integer(42)).unwrap(), 42);
279 assert_eq!(
280 String::from_value(&Value::Text("hello".to_string())).unwrap(),
281 "hello"
282 );
283 assert_eq!(
284 Option::<i64>::from_value(&Value::Integer(42)).unwrap(),
285 Some(42)
286 );
287 assert_eq!(Option::<i64>::from_value(&Value::Null).unwrap(), None);
288 }
289
290 #[test]
293 fn test_bool_to_value() {
294 assert_eq!(true.to_value(), Value::Boolean(true));
295 assert_eq!(false.to_value(), Value::Boolean(false));
296 }
297
298 #[test]
299 fn test_bool_column_type() {
300 assert_eq!(bool::column_type(), ColumnType::Boolean);
301 }
302
303 #[test]
304 fn test_bool_from_value() {
305 assert_eq!(bool::from_value(&Value::Boolean(true)).unwrap(), true);
306 assert_eq!(bool::from_value(&Value::Boolean(false)).unwrap(), false);
307 }
308
309 #[test]
310 fn test_bool_from_integer_truthiness() {
311 assert_eq!(bool::from_value(&Value::Integer(0)).unwrap(), false);
313 assert_eq!(bool::from_value(&Value::Integer(1)).unwrap(), true);
314 assert_eq!(bool::from_value(&Value::Integer(-1)).unwrap(), true);
315 assert_eq!(bool::from_value(&Value::Integer(42)).unwrap(), true);
316 }
317
318 #[test]
319 fn test_bool_from_null_error() {
320 let result = bool::from_value(&Value::Null);
321 assert!(result.is_err());
322 match result {
323 Err(Error::TypeError { expected, actual }) => {
324 assert_eq!(expected, "BOOLEAN");
325 assert_eq!(actual, "NULL");
326 }
327 _ => panic!("Expected TypeError"),
328 }
329 }
330
331 #[test]
332 fn test_bool_from_invalid_type() {
333 let result = bool::from_value(&Value::Text("true".to_string()));
334 assert!(result.is_err());
335 match result {
336 Err(Error::TypeError { expected, .. }) => {
337 assert_eq!(expected, "BOOLEAN");
338 }
339 _ => panic!("Expected TypeError"),
340 }
341 }
342
343 #[test]
346 fn test_i32_to_value() {
347 assert_eq!(42i32.to_value(), Value::Integer(42));
348 assert_eq!((-100i32).to_value(), Value::Integer(-100));
349 assert_eq!(0i32.to_value(), Value::Integer(0));
350 }
351
352 #[test]
353 fn test_i32_column_type() {
354 assert_eq!(i32::column_type(), ColumnType::Integer);
355 }
356
357 #[test]
358 fn test_i32_from_value() {
359 assert_eq!(i32::from_value(&Value::Integer(42)).unwrap(), 42);
360 assert_eq!(i32::from_value(&Value::Integer(-100)).unwrap(), -100);
361 }
362
363 #[test]
364 fn test_i32_from_real_casting() {
365 assert_eq!(i32::from_value(&Value::Real(3.7)).unwrap(), 3);
366 assert_eq!(i32::from_value(&Value::Real(-2.9)).unwrap(), -2);
367 assert_eq!(i32::from_value(&Value::Real(0.0)).unwrap(), 0);
368 }
369
370 #[test]
371 fn test_i32_from_null_error() {
372 let result = i32::from_value(&Value::Null);
373 assert!(result.is_err());
374 match result {
375 Err(Error::TypeError { expected, actual }) => {
376 assert_eq!(expected, "INTEGER");
377 assert_eq!(actual, "NULL");
378 }
379 _ => panic!("Expected TypeError"),
380 }
381 }
382
383 #[test]
384 fn test_i32_from_invalid_type() {
385 let result = i32::from_value(&Value::Text("42".to_string()));
386 assert!(result.is_err());
387 }
388
389 #[test]
392 fn test_f64_to_value() {
393 assert_eq!(3.14f64.to_value(), Value::Real(3.14));
394 assert_eq!((-2.5f64).to_value(), Value::Real(-2.5));
395 assert_eq!(0.0f64.to_value(), Value::Real(0.0));
396 }
397
398 #[test]
399 fn test_f64_column_type() {
400 assert_eq!(f64::column_type(), ColumnType::Real);
401 }
402
403 #[test]
404 fn test_f64_from_value() {
405 assert_eq!(f64::from_value(&Value::Real(3.14)).unwrap(), 3.14);
406 assert_eq!(f64::from_value(&Value::Real(-2.5)).unwrap(), -2.5);
407 }
408
409 #[test]
410 fn test_f64_from_integer_promotion() {
411 assert_eq!(f64::from_value(&Value::Integer(42)).unwrap(), 42.0);
412 assert_eq!(f64::from_value(&Value::Integer(-10)).unwrap(), -10.0);
413 assert_eq!(f64::from_value(&Value::Integer(0)).unwrap(), 0.0);
414 }
415
416 #[test]
417 fn test_f64_from_null_error() {
418 let result = f64::from_value(&Value::Null);
419 assert!(result.is_err());
420 match result {
421 Err(Error::TypeError { expected, actual }) => {
422 assert_eq!(expected, "REAL");
423 assert_eq!(actual, "NULL");
424 }
425 _ => panic!("Expected TypeError"),
426 }
427 }
428
429 #[test]
430 fn test_f64_from_invalid_type() {
431 let result = f64::from_value(&Value::Text("3.14".to_string()));
432 assert!(result.is_err());
433 }
434
435 #[test]
438 fn test_i64_column_type() {
439 assert_eq!(i64::column_type(), ColumnType::Integer);
440 }
441
442 #[test]
443 fn test_i64_from_real_casting() {
444 assert_eq!(i64::from_value(&Value::Real(100.9)).unwrap(), 100);
445 assert_eq!(i64::from_value(&Value::Real(-50.1)).unwrap(), -50);
446 }
447
448 #[test]
449 fn test_i64_from_null_error() {
450 let result = i64::from_value(&Value::Null);
451 assert!(result.is_err());
452 match result {
453 Err(Error::TypeError { expected, actual }) => {
454 assert_eq!(expected, "INTEGER");
455 assert_eq!(actual, "NULL");
456 }
457 _ => panic!("Expected TypeError"),
458 }
459 }
460
461 #[test]
464 fn test_blob_to_value() {
465 let blob = vec![0x01, 0x02, 0x03, 0xFF];
466 assert_eq!(blob.to_value(), Value::Blob(vec![0x01, 0x02, 0x03, 0xFF]));
467 }
468
469 #[test]
470 fn test_blob_empty_to_value() {
471 let blob: Vec<u8> = vec![];
472 assert_eq!(blob.to_value(), Value::Blob(vec![]));
473 }
474
475 #[test]
476 fn test_blob_column_type() {
477 assert_eq!(Vec::<u8>::column_type(), ColumnType::Blob { max_len: None });
478 }
479
480 #[test]
481 fn test_blob_from_value() {
482 let blob = vec![0xDE, 0xAD, 0xBE, 0xEF];
483 assert_eq!(
484 Vec::<u8>::from_value(&Value::Blob(blob.clone())).unwrap(),
485 blob
486 );
487 }
488
489 #[test]
490 fn test_blob_from_null_error() {
491 let result = Vec::<u8>::from_value(&Value::Null);
492 assert!(result.is_err());
493 match result {
494 Err(Error::TypeError { expected, actual }) => {
495 assert_eq!(expected, "BLOB");
496 assert_eq!(actual, "NULL");
497 }
498 _ => panic!("Expected TypeError"),
499 }
500 }
501
502 #[test]
503 fn test_blob_from_invalid_type() {
504 let result = Vec::<u8>::from_value(&Value::Text("hello".to_string()));
505 assert!(result.is_err());
506 }
507
508 #[test]
511 fn test_string_to_value() {
512 let s = String::from("hello world");
513 assert_eq!(s.to_value(), Value::Text("hello world".to_string()));
514 }
515
516 #[test]
517 fn test_string_column_type() {
518 assert_eq!(String::column_type(), ColumnType::Text { max_len: None });
519 }
520
521 #[test]
522 fn test_string_from_null_error() {
523 let result = String::from_value(&Value::Null);
524 assert!(result.is_err());
525 match result {
526 Err(Error::TypeError { expected, actual }) => {
527 assert_eq!(expected, "TEXT");
528 assert_eq!(actual, "NULL");
529 }
530 _ => panic!("Expected TypeError"),
531 }
532 }
533
534 #[test]
535 fn test_string_from_invalid_type() {
536 let result = String::from_value(&Value::Integer(42));
537 assert!(result.is_err());
538 }
539
540 #[test]
543 fn test_str_slice_to_value() {
544 let s: &str = "hello";
545 assert_eq!(s.to_value(), Value::Text("hello".to_string()));
546 }
547
548 #[test]
549 fn test_str_slice_column_type() {
550 assert_eq!(<&str>::column_type(), ColumnType::Text { max_len: None });
551 }
552
553 #[test]
556 fn test_option_to_value_with_value() {
557 assert_eq!(Some(42i64).to_value(), Value::Integer(42));
558 assert_eq!(
559 Some("hello".to_string()).to_value(),
560 Value::Text("hello".to_string())
561 );
562 assert_eq!(Some(true).to_value(), Value::Boolean(true));
563 assert_eq!(Some(3.14f64).to_value(), Value::Real(3.14));
564 }
565
566 #[test]
567 fn test_option_to_value_none() {
568 assert_eq!(None::<i64>.to_value(), Value::Null);
569 assert_eq!(None::<String>.to_value(), Value::Null);
570 assert_eq!(None::<bool>.to_value(), Value::Null);
571 assert_eq!(None::<f64>.to_value(), Value::Null);
572 }
573
574 #[test]
575 fn test_option_column_type() {
576 assert_eq!(Option::<i64>::column_type(), ColumnType::Integer);
577 assert_eq!(
578 Option::<String>::column_type(),
579 ColumnType::Text { max_len: None }
580 );
581 assert_eq!(Option::<bool>::column_type(), ColumnType::Boolean);
582 assert_eq!(Option::<f64>::column_type(), ColumnType::Real);
583 }
584
585 #[test]
586 fn test_option_from_value() {
587 assert_eq!(Option::<i64>::from_value(&Value::Null).unwrap(), None);
588 assert_eq!(
589 Option::<i64>::from_value(&Value::Integer(42)).unwrap(),
590 Some(42)
591 );
592 assert_eq!(
593 Option::<String>::from_value(&Value::Text("hello".to_string())).unwrap(),
594 Some("hello".to_string())
595 );
596 assert_eq!(
597 Option::<bool>::from_value(&Value::Boolean(true)).unwrap(),
598 Some(true)
599 );
600 }
601
602 #[test]
605 fn test_column_def_creation() {
606 let col = ColumnDef {
607 name: "id",
608 column_type: ColumnType::Integer,
609 primary_key: true,
610 not_null: true,
611 unique: true,
612 default: None,
613 };
614
615 assert_eq!(col.name, "id");
616 assert_eq!(col.column_type, ColumnType::Integer);
617 assert!(col.primary_key);
618 assert!(col.not_null);
619 assert!(col.unique);
620 assert!(col.default.is_none());
621 }
622
623 #[test]
624 fn test_column_def_with_default() {
625 let col = ColumnDef {
626 name: "status",
627 column_type: ColumnType::Text { max_len: Some(50) },
628 primary_key: false,
629 not_null: true,
630 unique: false,
631 default: Some(Value::Text("active".to_string())),
632 };
633
634 assert_eq!(col.name, "status");
635 assert!(matches!(
636 col.column_type,
637 ColumnType::Text { max_len: Some(50) }
638 ));
639 assert!(!col.primary_key);
640 assert!(col.not_null);
641 assert!(!col.unique);
642 assert_eq!(col.default, Some(Value::Text("active".to_string())));
643 }
644
645 #[test]
646 fn test_column_def_clone() {
647 let col = ColumnDef {
648 name: "amount",
649 column_type: ColumnType::Real,
650 primary_key: false,
651 not_null: false,
652 unique: false,
653 default: Some(Value::Real(0.0)),
654 };
655
656 let cloned = col.clone();
657 assert_eq!(col.name, cloned.name);
658 assert_eq!(col.column_type, cloned.column_type);
659 assert_eq!(col.default, cloned.default);
660 }
661
662 #[test]
663 fn test_column_def_debug() {
664 let col = ColumnDef {
665 name: "test",
666 column_type: ColumnType::Integer,
667 primary_key: false,
668 not_null: false,
669 unique: false,
670 default: None,
671 };
672
673 let debug_str = format!("{:?}", col);
675 assert!(debug_str.contains("test"));
676 }
677}