1use crate::value::Value;
41use std::collections::HashMap;
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
51pub enum CastType {
52 Integer,
54 Float,
56 Boolean,
58 String,
60 Json,
62 DateTime,
64 Date,
66 Time,
68 Bytes,
70 Array,
72}
73
74impl CastType {
75 pub fn name(&self) -> &'static str {
77 match self {
78 CastType::Integer => "integer",
79 CastType::Float => "float",
80 CastType::Boolean => "boolean",
81 CastType::String => "string",
82 CastType::Json => "json",
83 CastType::DateTime => "datetime",
84 CastType::Date => "date",
85 CastType::Time => "time",
86 CastType::Bytes => "bytes",
87 CastType::Array => "array",
88 }
89 }
90}
91
92pub trait Accessor: Send + Sync {
100 fn field(&self) -> &str;
102
103 fn read(&self, value: Value) -> Value;
105}
106
107pub trait Mutator: Send + Sync {
111 fn field(&self) -> &str;
113
114 fn write(&self, value: Value) -> Value;
116}
117
118pub struct ClosureAccessor {
124 pub field_name: String,
126 pub reader: Box<dyn Fn(Value) -> Value + Send + Sync>,
128}
129
130impl ClosureAccessor {
131 pub fn new(
133 field: impl Into<String>,
134 reader: impl Fn(Value) -> Value + Send + Sync + 'static,
135 ) -> Self {
136 Self {
137 field_name: field.into(),
138 reader: Box::new(reader),
139 }
140 }
141}
142
143impl Accessor for ClosureAccessor {
144 fn field(&self) -> &str {
145 &self.field_name
146 }
147
148 fn read(&self, value: Value) -> Value {
149 (self.reader)(value)
150 }
151}
152
153pub struct ClosureMutator {
155 pub field_name: String,
157 pub writer: Box<dyn Fn(Value) -> Value + Send + Sync>,
159}
160
161impl ClosureMutator {
162 pub fn new(
164 field: impl Into<String>,
165 writer: impl Fn(Value) -> Value + Send + Sync + 'static,
166 ) -> Self {
167 Self {
168 field_name: field.into(),
169 writer: Box::new(writer),
170 }
171 }
172}
173
174impl Mutator for ClosureMutator {
175 fn field(&self) -> &str {
176 &self.field_name
177 }
178
179 fn write(&self, value: Value) -> Value {
180 (self.writer)(value)
181 }
182}
183
184pub struct AttributeCaster;
192
193impl AttributeCaster {
194 pub fn cast_read(value: Value, target: CastType) -> Value {
196 match target {
197 CastType::Integer => Self::to_integer(value),
198 CastType::Float => Self::to_float(value),
199 CastType::Boolean => Self::to_boolean(value),
200 CastType::String => Self::to_string_value(value),
201 CastType::Json => Self::to_json(value),
202 CastType::DateTime => Self::to_datetime(value),
203 CastType::Date => Self::to_date(value),
204 CastType::Time => Self::to_time(value),
205 CastType::Bytes => Self::to_bytes(value),
206 CastType::Array => Self::to_array(value),
207 }
208 }
209
210 pub fn cast_write(value: Value, target: CastType) -> Value {
212 match target {
213 CastType::Integer => Self::to_integer(value),
214 CastType::Float => Self::to_float(value),
215 CastType::Boolean => Self::to_boolean_storage(value),
216 CastType::String => Self::to_string_value(value),
217 CastType::Json => Self::to_json_storage(value),
218 CastType::DateTime => Self::to_datetime_storage(value),
219 CastType::Date => Self::to_date_storage(value),
220 CastType::Time => Self::to_time_storage(value),
221 CastType::Bytes => Self::to_bytes(value),
222 CastType::Array => Self::to_array_storage(value),
223 }
224 }
225
226 fn to_integer(value: Value) -> Value {
229 match value {
230 Value::I64(_) | Value::I32(_) | Value::I8(_) | Value::I16(_) => value,
231 Value::U32(v) => Value::I64(v as i64),
232 Value::U64(v) => Value::I64(v as i64),
233 Value::U8(v) => Value::I64(v as i64),
234 Value::U16(v) => Value::I64(v as i64),
235 Value::F32(v) => Value::I64(v as i64),
236 Value::F64(v) => Value::I64(v as i64),
237 Value::Bool(b) => Value::I64(if b { 1 } else { 0 }),
238 Value::String(s) => {
239 if let Ok(n) = s.trim().parse::<i64>() {
240 Value::I64(n)
241 } else {
242 Value::Null
243 }
244 }
245 Value::Null => Value::Null,
246 _ => Value::Null,
247 }
248 }
249
250 fn to_float(value: Value) -> Value {
251 match value {
252 Value::F32(_) | Value::F64(_) => value,
253 Value::I64(v) => Value::F64(v as f64),
254 Value::I32(v) => Value::F64(v as f64),
255 Value::I8(v) => Value::F64(v as f64),
256 Value::I16(v) => Value::F64(v as f64),
257 Value::U32(v) => Value::F64(v as f64),
258 Value::U64(v) => Value::F64(v as f64),
259 Value::U8(v) => Value::F64(v as f64),
260 Value::U16(v) => Value::F64(v as f64),
261 Value::Bool(b) => Value::F64(if b { 1.0 } else { 0.0 }),
262 Value::String(s) => {
263 if let Ok(n) = s.trim().parse::<f64>() {
264 Value::F64(n)
265 } else {
266 Value::Null
267 }
268 }
269 Value::Null => Value::Null,
270 _ => Value::Null,
271 }
272 }
273
274 fn to_boolean(value: Value) -> Value {
275 match value {
276 Value::Bool(_) => value,
277 Value::I64(v) => Value::Bool(v != 0),
278 Value::I32(v) => Value::Bool(v != 0),
279 Value::I8(v) => Value::Bool(v != 0),
280 Value::I16(v) => Value::Bool(v != 0),
281 Value::U32(v) => Value::Bool(v != 0),
282 Value::U64(v) => Value::Bool(v != 0),
283 Value::U8(v) => Value::Bool(v != 0),
284 Value::U16(v) => Value::Bool(v != 0),
285 Value::F32(v) => Value::Bool(v != 0.0),
286 Value::F64(v) => Value::Bool(v != 0.0),
287 Value::String(s) => {
288 let lower = s.trim().to_lowercase();
289 Value::Bool(matches!(
290 lower.as_str(),
291 "1" | "true" | "yes" | "on" | "y" | "t"
292 ))
293 }
294 Value::Null => Value::Null,
295 _ => Value::Null,
296 }
297 }
298
299 fn to_boolean_storage(value: Value) -> Value {
300 match value {
301 Value::Bool(b) => Value::I64(if b { 1 } else { 0 }),
302 Value::I64(_) | Value::I32(_) | Value::I8(_) | Value::I16(_) => value,
303 Value::U32(v) => Value::I64(if v != 0 { 1 } else { 0 }),
304 Value::U64(v) => Value::I64(if v != 0 { 1 } else { 0 }),
305 Value::U8(v) => Value::I64(if v != 0 { 1 } else { 0 }),
306 Value::U16(v) => Value::I64(if v != 0 { 1 } else { 0 }),
307 Value::F32(v) => Value::I64(if v != 0.0 { 1 } else { 0 }),
308 Value::F64(v) => Value::I64(if v != 0.0 { 1 } else { 0 }),
309 Value::String(s) => {
310 let lower = s.trim().to_lowercase();
311 Value::I64(
312 if matches!(lower.as_str(), "1" | "true" | "yes" | "on" | "y" | "t") {
313 1
314 } else {
315 0
316 },
317 )
318 }
319 Value::Null => Value::Null,
320 _ => Value::Null,
321 }
322 }
323
324 fn to_string_value(value: Value) -> Value {
325 match value {
326 Value::String(_) => value,
327 Value::I64(v) => Value::String(v.to_string()),
328 Value::I32(v) => Value::String(v.to_string()),
329 Value::I8(v) => Value::String(v.to_string()),
330 Value::I16(v) => Value::String(v.to_string()),
331 Value::U32(v) => Value::String(v.to_string()),
332 Value::U64(v) => Value::String(v.to_string()),
333 Value::U8(v) => Value::String(v.to_string()),
334 Value::U16(v) => Value::String(v.to_string()),
335 Value::F32(v) => Value::String(v.to_string()),
336 Value::F64(v) => Value::String(v.to_string()),
337 Value::Bool(b) => Value::String(b.to_string()),
338 Value::Null => Value::Null,
339 other => Value::String(format!("{:?}", other)),
340 }
341 }
342
343 fn to_json(value: Value) -> Value {
344 match value {
345 Value::String(s) => {
346 if serde_json::from_str::<serde_json::Value>(&s).is_ok() {
348 Value::Json(s)
349 } else {
350 Value::String(s)
351 }
352 }
353 Value::Json(s) => Value::Json(s),
354 other => Value::Json(value_to_json_string(&other)),
355 }
356 }
357
358 fn to_json_storage(value: Value) -> Value {
359 match value {
360 Value::Json(s) => Value::Json(s),
361 Value::String(s) => Value::Json(s),
362 other => Value::Json(value_to_json_string(&other)),
363 }
364 }
365
366 fn to_datetime(value: Value) -> Value {
367 match value {
368 Value::DateTime(s) => Value::DateTime(s),
369 Value::String(s) => Value::DateTime(s),
370 Value::Null => Value::Null,
371 other => Value::DateTime(format!("{:?}", other)),
372 }
373 }
374
375 fn to_datetime_storage(value: Value) -> Value {
376 match value {
377 Value::DateTime(s) => Value::DateTime(s),
378 Value::String(s) => Value::DateTime(s),
379 Value::Null => Value::Null,
380 other => Value::DateTime(format!("{:?}", other)),
381 }
382 }
383
384 fn to_date(value: Value) -> Value {
385 match value {
386 Value::Date(s) => Value::Date(s),
387 Value::String(s) => Value::Date(s),
388 Value::Null => Value::Null,
389 other => Value::Date(format!("{:?}", other)),
390 }
391 }
392
393 fn to_date_storage(value: Value) -> Value {
394 match value {
395 Value::Date(s) => Value::Date(s),
396 Value::String(s) => Value::Date(s),
397 Value::Null => Value::Null,
398 other => Value::Date(format!("{:?}", other)),
399 }
400 }
401
402 fn to_time(value: Value) -> Value {
403 match value {
404 Value::Time(s) => Value::Time(s),
405 Value::String(s) => Value::Time(s),
406 Value::Null => Value::Null,
407 other => Value::Time(format!("{:?}", other)),
408 }
409 }
410
411 fn to_time_storage(value: Value) -> Value {
412 match value {
413 Value::Time(s) => Value::Time(s),
414 Value::String(s) => Value::Time(s),
415 Value::Null => Value::Null,
416 other => Value::Time(format!("{:?}", other)),
417 }
418 }
419
420 fn to_bytes(value: Value) -> Value {
421 match value {
422 Value::Bytes(_) => value,
423 Value::String(s) => Value::Bytes(s.into_bytes()),
424 Value::Null => Value::Null,
425 _ => Value::Null,
426 }
427 }
428
429 fn to_array(value: Value) -> Value {
430 match value {
431 Value::Array(_) => value,
432 Value::Json(s) => {
433 match serde_json::from_str::<Vec<serde_json::Value>>(&s) {
435 Ok(json_arr) => {
436 let items: Vec<Value> = json_arr.into_iter().map(json_to_value).collect();
437 Value::Array(items)
438 }
439 Err(_) => Value::Array(vec![Value::Json(s)]),
440 }
441 }
442 Value::String(s) => {
443 match serde_json::from_str::<Vec<serde_json::Value>>(&s) {
445 Ok(json_arr) => {
446 let items: Vec<Value> = json_arr.into_iter().map(json_to_value).collect();
447 Value::Array(items)
448 }
449 Err(_) => Value::Array(vec![Value::String(s)]),
450 }
451 }
452 Value::Null => Value::Null,
453 other => Value::Array(vec![other]),
454 }
455 }
456
457 fn to_array_storage(value: Value) -> Value {
458 match value {
459 Value::Array(items) => {
460 let json_arr: Vec<serde_json::Value> = items.iter().map(value_to_json).collect();
462 Value::Json(serde_json::to_string(&json_arr).unwrap_or_else(|_| "[]".to_string()))
463 }
464 other => Value::Json(value_to_json_string(&other)),
465 }
466 }
467}
468
469fn value_to_json(value: &Value) -> serde_json::Value {
473 match value {
474 Value::Null => serde_json::Value::Null,
475 Value::Bool(b) => serde_json::Value::Bool(*b),
476 Value::I8(v) => serde_json::Value::Number((*v).into()),
477 Value::I16(v) => serde_json::Value::Number((*v).into()),
478 Value::I32(v) => serde_json::Value::Number((*v).into()),
479 Value::I64(v) => serde_json::Value::Number((*v).into()),
480 Value::U8(v) => serde_json::Value::Number((*v).into()),
481 Value::U16(v) => serde_json::Value::Number((*v).into()),
482 Value::U32(v) => serde_json::Value::Number((*v).into()),
483 Value::U64(v) => serde_json::Value::Number((*v).into()),
484 Value::F32(v) => serde_json::Number::from_f64(*v as f64)
485 .map(serde_json::Value::Number)
486 .unwrap_or(serde_json::Value::Null),
487 Value::F64(v) => serde_json::Number::from_f64(*v)
488 .map(serde_json::Value::Number)
489 .unwrap_or(serde_json::Value::Null),
490 Value::Decimal(s) => {
491 serde_json::from_str(s).unwrap_or_else(|_| serde_json::Value::String(s.clone()))
493 }
494 Value::String(s) => serde_json::Value::String(s.clone()),
495 Value::Bytes(b) => {
496 use std::fmt::Write;
498 let mut s = String::with_capacity(b.len() * 2);
499 for byte in b {
500 let _ = write!(&mut s, "{:02x}", byte);
501 }
502 serde_json::Value::String(s)
503 }
504 Value::Uuid(s) => serde_json::Value::String(s.clone()),
505 Value::Date(s) => serde_json::Value::String(s.clone()),
506 Value::DateTime(s) => serde_json::Value::String(s.clone()),
507 Value::Time(s) => serde_json::Value::String(s.clone()),
508 Value::Json(s) => serde_json::from_str(s).unwrap_or(serde_json::Value::String(s.clone())),
509 Value::Array(items) => serde_json::Value::Array(items.iter().map(value_to_json).collect()),
510 Value::Object(map) => {
511 let mut obj = serde_json::Map::new();
512 for (k, v) in map {
513 obj.insert(k.clone(), value_to_json(v));
514 }
515 serde_json::Value::Object(obj)
516 }
517 }
518}
519
520fn value_to_json_string(value: &Value) -> String {
522 serde_json::to_string(&value_to_json(value)).unwrap_or_else(|_| "null".to_string())
523}
524
525fn json_to_value(jv: serde_json::Value) -> Value {
529 match jv {
530 serde_json::Value::Null => Value::Null,
531 serde_json::Value::Bool(b) => Value::Bool(b),
532 serde_json::Value::Number(n) => {
533 if let Some(i) = n.as_i64() {
534 Value::I64(i)
535 } else if let Some(u) = n.as_u64() {
536 Value::U64(u)
537 } else if let Some(f) = n.as_f64() {
538 Value::F64(f)
539 } else {
540 Value::Null
541 }
542 }
543 serde_json::Value::String(s) => Value::String(s),
544 serde_json::Value::Array(arr) => Value::Array(arr.into_iter().map(json_to_value).collect()),
545 serde_json::Value::Object(obj) => {
546 let mut map = std::collections::HashMap::new();
547 for (k, v) in obj {
548 map.insert(k, json_to_value(v));
549 }
550 Value::Object(map)
551 }
552 }
553}
554
555pub struct AccessorRegistry {
563 accessors: HashMap<String, Box<dyn Accessor>>,
565 mutators: HashMap<String, Box<dyn Mutator>>,
567 casts: HashMap<String, CastType>,
569}
570
571impl Default for AccessorRegistry {
572 fn default() -> Self {
573 Self::new()
574 }
575}
576
577impl AccessorRegistry {
578 pub fn new() -> Self {
580 Self {
581 accessors: HashMap::new(),
582 mutators: HashMap::new(),
583 casts: HashMap::new(),
584 }
585 }
586
587 pub fn register_accessor(&mut self, accessor: Box<dyn Accessor>) {
589 let field = accessor.field().to_string();
590 self.accessors.insert(field, accessor);
591 }
592
593 pub fn register_mutator(&mut self, mutator: Box<dyn Mutator>) {
595 let field = mutator.field().to_string();
596 self.mutators.insert(field, mutator);
597 }
598
599 pub fn register_cast(&mut self, field: impl Into<String>, cast: CastType) {
601 self.casts.insert(field.into(), cast);
602 }
603
604 pub fn read(&self, field: &str, value: Value) -> Value {
606 let v1 = if let Some(cast) = self.casts.get(field) {
607 AttributeCaster::cast_read(value, *cast)
608 } else {
609 value
610 };
611 if let Some(accessor) = self.accessors.get(field) {
612 accessor.read(v1)
613 } else {
614 v1
615 }
616 }
617
618 pub fn write(&self, field: &str, value: Value) -> Value {
620 let v1 = if let Some(mutator) = self.mutators.get(field) {
621 mutator.write(value)
622 } else {
623 value
624 };
625 if let Some(cast) = self.casts.get(field) {
626 AttributeCaster::cast_write(v1, *cast)
627 } else {
628 v1
629 }
630 }
631
632 pub fn cast_read(&self, field: &str, value: Value) -> Value {
634 if let Some(cast) = self.casts.get(field) {
635 AttributeCaster::cast_read(value, *cast)
636 } else {
637 value
638 }
639 }
640
641 pub fn cast_write(&self, field: &str, value: Value) -> Value {
643 if let Some(cast) = self.casts.get(field) {
644 AttributeCaster::cast_write(value, *cast)
645 } else {
646 value
647 }
648 }
649
650 pub fn has_accessor(&self, field: &str) -> bool {
652 self.accessors.contains_key(field)
653 }
654
655 pub fn has_mutator(&self, field: &str) -> bool {
657 self.mutators.contains_key(field)
658 }
659
660 pub fn has_cast(&self, field: &str) -> bool {
662 self.casts.contains_key(field)
663 }
664
665 pub fn get_cast(&self, field: &str) -> Option<CastType> {
667 self.casts.get(field).copied()
668 }
669
670 pub fn accessor_count(&self) -> usize {
672 self.accessors.len()
673 }
674
675 pub fn mutator_count(&self) -> usize {
677 self.mutators.len()
678 }
679
680 pub fn cast_count(&self) -> usize {
682 self.casts.len()
683 }
684}
685
686#[cfg(test)]
691mod tests {
692 use super::*;
693
694 #[test]
697 fn test_cast_type_name() {
698 assert_eq!(CastType::Integer.name(), "integer");
699 assert_eq!(CastType::Boolean.name(), "boolean");
700 assert_eq!(CastType::Json.name(), "json");
701 assert_eq!(CastType::DateTime.name(), "datetime");
702 }
703
704 #[test]
707 fn test_cast_to_integer_from_string() {
708 let v = AttributeCaster::cast_read(Value::String("42".to_string()), CastType::Integer);
709 assert_eq!(v, Value::I64(42));
710 }
711
712 #[test]
713 fn test_cast_to_integer_from_invalid_string() {
714 let v = AttributeCaster::cast_read(Value::String("abc".to_string()), CastType::Integer);
715 assert_eq!(v, Value::Null);
716 }
717
718 #[test]
719 fn test_cast_to_integer_from_bool() {
720 let v = AttributeCaster::cast_read(Value::Bool(true), CastType::Integer);
721 assert_eq!(v, Value::I64(1));
722 }
723
724 #[test]
725 fn test_cast_to_integer_from_float() {
726 let v = AttributeCaster::cast_read(Value::F64(3.7), CastType::Integer);
727 assert_eq!(v, Value::I64(3));
728 }
729
730 #[test]
731 fn test_cast_to_integer_preserves_i64() {
732 let v = AttributeCaster::cast_read(Value::I64(100), CastType::Integer);
733 assert_eq!(v, Value::I64(100));
734 }
735
736 #[test]
739 fn test_cast_to_float_from_string() {
740 let v = AttributeCaster::cast_read(Value::String("3.15".to_string()), CastType::Float);
741 assert_eq!(v, Value::F64(3.15));
742 }
743
744 #[test]
745 fn test_cast_to_float_from_i64() {
746 let v = AttributeCaster::cast_read(Value::I64(42), CastType::Float);
747 assert_eq!(v, Value::F64(42.0));
748 }
749
750 #[test]
753 fn test_cast_to_boolean_from_i64_one() {
754 let v = AttributeCaster::cast_read(Value::I64(1), CastType::Boolean);
755 assert_eq!(v, Value::Bool(true));
756 }
757
758 #[test]
759 fn test_cast_to_boolean_from_i64_zero() {
760 let v = AttributeCaster::cast_read(Value::I64(0), CastType::Boolean);
761 assert_eq!(v, Value::Bool(false));
762 }
763
764 #[test]
765 fn test_cast_to_boolean_from_string_true() {
766 let v = AttributeCaster::cast_read(Value::String("true".to_string()), CastType::Boolean);
767 assert_eq!(v, Value::Bool(true));
768 }
769
770 #[test]
771 fn test_cast_to_boolean_from_string_yes() {
772 let v = AttributeCaster::cast_read(Value::String("yes".to_string()), CastType::Boolean);
773 assert_eq!(v, Value::Bool(true));
774 }
775
776 #[test]
777 fn test_cast_to_boolean_from_string_on() {
778 let v = AttributeCaster::cast_read(Value::String("on".to_string()), CastType::Boolean);
779 assert_eq!(v, Value::Bool(true));
780 }
781
782 #[test]
783 fn test_cast_to_boolean_from_string_random() {
784 let v = AttributeCaster::cast_read(Value::String("random".to_string()), CastType::Boolean);
785 assert_eq!(v, Value::Bool(false));
786 }
787
788 #[test]
789 fn test_cast_to_boolean_preserves_bool() {
790 let v = AttributeCaster::cast_read(Value::Bool(true), CastType::Boolean);
791 assert_eq!(v, Value::Bool(true));
792 }
793
794 #[test]
797 fn test_cast_to_boolean_storage_from_bool() {
798 let v = AttributeCaster::cast_write(Value::Bool(true), CastType::Boolean);
799 assert_eq!(v, Value::I64(1));
800 }
801
802 #[test]
803 fn test_cast_to_boolean_storage_from_string() {
804 let v = AttributeCaster::cast_write(Value::String("yes".to_string()), CastType::Boolean);
805 assert_eq!(v, Value::I64(1));
806 }
807
808 #[test]
811 fn test_cast_to_string_from_i64() {
812 let v = AttributeCaster::cast_read(Value::I64(42), CastType::String);
813 assert_eq!(v, Value::String("42".to_string()));
814 }
815
816 #[test]
817 fn test_cast_to_string_from_bool() {
818 let v = AttributeCaster::cast_read(Value::Bool(true), CastType::String);
819 assert_eq!(v, Value::String("true".to_string()));
820 }
821
822 #[test]
823 fn test_cast_to_string_preserves_string() {
824 let v = AttributeCaster::cast_read(Value::String("hello".to_string()), CastType::String);
825 assert_eq!(v, Value::String("hello".to_string()));
826 }
827
828 #[test]
831 fn test_cast_to_json_from_string() {
832 let v = AttributeCaster::cast_read(
833 Value::String(r#"{"key":"value"}"#.to_string()),
834 CastType::Json,
835 );
836 assert!(matches!(v, Value::Json(_)));
838 if let Value::Json(s) = v {
839 let parsed: serde_json::Value = serde_json::from_str(&s).unwrap();
841 assert_eq!(parsed["key"], "value");
842 }
843 }
844
845 #[test]
846 fn test_cast_to_json_from_invalid_string() {
847 let v = AttributeCaster::cast_read(Value::String("not a json".to_string()), CastType::Json);
848 assert!(matches!(v, Value::String(_)));
850 }
851
852 #[test]
853 fn test_cast_to_json_from_other() {
854 let v = AttributeCaster::cast_read(Value::I64(42), CastType::Json);
855 assert!(matches!(v, Value::Json(_)));
856 if let Value::Json(s) = v {
857 let parsed: serde_json::Value = serde_json::from_str(&s).unwrap();
859 assert_eq!(parsed, serde_json::Value::Number(42.into()));
860 }
861 }
862
863 #[test]
866 fn test_cast_to_datetime_from_string() {
867 let v = AttributeCaster::cast_read(
868 Value::String("2026-07-19T10:00:00Z".to_string()),
869 CastType::DateTime,
870 );
871 assert_eq!(v, Value::DateTime("2026-07-19T10:00:00Z".to_string()));
872 }
873
874 #[test]
875 fn test_cast_to_date_from_string() {
876 let v = AttributeCaster::cast_read(Value::String("2026-07-19".to_string()), CastType::Date);
877 assert_eq!(v, Value::Date("2026-07-19".to_string()));
878 }
879
880 #[test]
881 fn test_cast_to_time_from_string() {
882 let v = AttributeCaster::cast_read(Value::String("10:30:00".to_string()), CastType::Time);
883 assert_eq!(v, Value::Time("10:30:00".to_string()));
884 }
885
886 #[test]
889 fn test_cast_to_bytes_from_string() {
890 let v = AttributeCaster::cast_read(Value::String("hello".to_string()), CastType::Bytes);
891 assert_eq!(v, Value::Bytes(b"hello".to_vec()));
892 }
893
894 #[test]
895 fn test_cast_to_bytes_preserves_bytes() {
896 let v = AttributeCaster::cast_read(Value::Bytes(b"data".to_vec()), CastType::Bytes);
897 assert_eq!(v, Value::Bytes(b"data".to_vec()));
898 }
899
900 #[test]
903 fn test_cast_to_array_from_string() {
904 let v = AttributeCaster::cast_read(Value::String("item".to_string()), CastType::Array);
905 assert!(matches!(v, Value::Array(_)));
906 if let Value::Array(arr) = v {
907 assert_eq!(arr.len(), 1);
908 }
909 }
910
911 #[test]
912 fn test_cast_to_array_from_json_string() {
913 let v = AttributeCaster::cast_read(Value::String("[1, 2, 3]".to_string()), CastType::Array);
915 assert!(matches!(v, Value::Array(_)));
916 if let Value::Array(arr) = v {
917 assert_eq!(arr.len(), 3);
918 assert_eq!(arr[0], Value::I64(1));
919 assert_eq!(arr[1], Value::I64(2));
920 assert_eq!(arr[2], Value::I64(3));
921 }
922 }
923
924 #[test]
925 fn test_cast_to_array_from_json_value() {
926 let v =
928 AttributeCaster::cast_read(Value::Json(r#"["a", "b"]"#.to_string()), CastType::Array);
929 assert!(matches!(v, Value::Array(_)));
930 if let Value::Array(arr) = v {
931 assert_eq!(arr.len(), 2);
932 assert_eq!(arr[0], Value::String("a".to_string()));
933 assert_eq!(arr[1], Value::String("b".to_string()));
934 }
935 }
936
937 #[test]
938 fn test_cast_to_array_preserves_array() {
939 let arr = vec![Value::I64(1), Value::I64(2)];
940 let v = AttributeCaster::cast_read(Value::Array(arr.clone()), CastType::Array);
941 assert_eq!(v, Value::Array(arr));
942 }
943
944 #[test]
945 fn test_cast_to_array_storage_serializes_to_json() {
946 let v = AttributeCaster::cast_write(
947 Value::Array(vec![Value::I64(1), Value::I64(2)]),
948 CastType::Array,
949 );
950 assert!(matches!(v, Value::Json(_)));
951 if let Value::Json(s) = v {
952 let parsed: serde_json::Value = serde_json::from_str(&s).unwrap();
954 assert!(parsed.is_array());
955 assert_eq!(parsed[0], serde_json::Value::Number(1.into()));
956 assert_eq!(parsed[1], serde_json::Value::Number(2.into()));
957 }
958 }
959
960 #[test]
961 fn test_cast_to_array_storage_not_debug_format() {
962 let v = AttributeCaster::cast_write(
964 Value::Array(vec![Value::I64(1), Value::I64(2)]),
965 CastType::Array,
966 );
967 if let Value::Json(s) = v {
968 assert!(!s.contains("I64"), "JSON 不应包含 Debug 格式 I64: {}", s);
970 let parsed: serde_json::Value = serde_json::from_str(&s).unwrap();
972 assert!(parsed.is_array());
973 }
974 }
975
976 #[test]
977 fn test_cast_to_json_storage_from_other() {
978 let v = AttributeCaster::cast_write(Value::I64(42), CastType::Json);
979 assert!(matches!(v, Value::Json(_)));
980 if let Value::Json(s) = v {
981 let parsed: serde_json::Value = serde_json::from_str(&s).unwrap();
983 assert_eq!(parsed, serde_json::Value::Number(42.into()));
984 }
985 }
986
987 #[test]
990 fn test_closure_accessor() {
991 let accessor = ClosureAccessor::new("name", |v| match v {
992 Value::String(s) => Value::String(s.to_uppercase()),
993 other => other,
994 });
995 let v = accessor.read(Value::String("alice".to_string()));
996 assert_eq!(v, Value::String("ALICE".to_string()));
997 assert_eq!(accessor.field(), "name");
998 }
999
1000 #[test]
1001 fn test_closure_mutator() {
1002 let mutator = ClosureMutator::new("email", |v| match v {
1003 Value::String(s) => Value::String(s.to_lowercase()),
1004 other => other,
1005 });
1006 let v = mutator.write(Value::String("ALICE@EXAMPLE.COM".to_string()));
1007 assert_eq!(v, Value::String("alice@example.com".to_string()));
1008 assert_eq!(mutator.field(), "email");
1009 }
1010
1011 #[test]
1014 fn test_registry_empty() {
1015 let r = AccessorRegistry::new();
1016 assert_eq!(r.accessor_count(), 0);
1017 assert_eq!(r.mutator_count(), 0);
1018 assert_eq!(r.cast_count(), 0);
1019 }
1020
1021 #[test]
1022 fn test_registry_register_cast() {
1023 let mut r = AccessorRegistry::new();
1024 r.register_cast("is_admin", CastType::Boolean);
1025 assert!(r.has_cast("is_admin"));
1026 assert_eq!(r.get_cast("is_admin"), Some(CastType::Boolean));
1027 assert_eq!(r.cast_count(), 1);
1028 }
1029
1030 #[test]
1031 fn test_registry_register_accessor() {
1032 let mut r = AccessorRegistry::new();
1033 r.register_accessor(Box::new(ClosureAccessor::new("name", |v| match v {
1034 Value::String(s) => Value::String(s.to_uppercase()),
1035 other => other,
1036 })));
1037 assert!(r.has_accessor("name"));
1038 assert_eq!(r.accessor_count(), 1);
1039 }
1040
1041 #[test]
1042 fn test_registry_register_mutator() {
1043 let mut r = AccessorRegistry::new();
1044 r.register_mutator(Box::new(ClosureMutator::new("email", |v| match v {
1045 Value::String(s) => Value::String(s.to_lowercase()),
1046 other => other,
1047 })));
1048 assert!(r.has_mutator("email"));
1049 assert_eq!(r.mutator_count(), 1);
1050 }
1051
1052 #[test]
1055 fn test_registry_read_applies_cast_then_accessor() {
1056 let mut r = AccessorRegistry::new();
1057 r.register_cast("is_admin", CastType::Boolean);
1058 r.register_accessor(Box::new(ClosureAccessor::new("is_admin", |v| {
1059 if v == Value::Bool(true) {
1060 Value::String("管理员".to_string())
1061 } else {
1062 Value::String("普通用户".to_string())
1063 }
1064 })));
1065
1066 let v = r.read("is_admin", Value::I64(1));
1068 assert_eq!(v, Value::String("管理员".to_string()));
1069 }
1070
1071 #[test]
1072 fn test_registry_write_applies_mutator_then_cast() {
1073 let mut r = AccessorRegistry::new();
1074 r.register_cast("is_admin", CastType::Boolean);
1075 r.register_mutator(Box::new(ClosureMutator::new("is_admin", |v| match v {
1076 Value::String(s) => {
1077 let lower = s.to_lowercase();
1078 Value::Bool(lower == "admin" || lower == "true")
1079 }
1080 other => other,
1081 })));
1082
1083 let v = r.write("is_admin", Value::String("admin".to_string()));
1085 assert_eq!(v, Value::I64(1));
1086 }
1087
1088 #[test]
1089 fn test_registry_read_without_cast_or_accessor() {
1090 let r = AccessorRegistry::new();
1091 let v = r.read("any_field", Value::I64(42));
1092 assert_eq!(v, Value::I64(42));
1093 }
1094
1095 #[test]
1096 fn test_registry_write_without_cast_or_mutator() {
1097 let r = AccessorRegistry::new();
1098 let v = r.write("any_field", Value::I64(42));
1099 assert_eq!(v, Value::I64(42));
1100 }
1101
1102 #[test]
1103 fn test_registry_cast_read_only() {
1104 let mut r = AccessorRegistry::new();
1105 r.register_cast("is_admin", CastType::Boolean);
1106
1107 let v = r.cast_read("is_admin", Value::I64(1));
1108 assert_eq!(v, Value::Bool(true));
1109 }
1110
1111 #[test]
1112 fn test_registry_cast_write_only() {
1113 let mut r = AccessorRegistry::new();
1114 r.register_cast("is_admin", CastType::Boolean);
1115
1116 let v = r.cast_write("is_admin", Value::Bool(true));
1117 assert_eq!(v, Value::I64(1));
1118 }
1119
1120 #[test]
1123 fn test_complex_user_model_scenario() {
1124 let mut r = AccessorRegistry::new();
1125
1126 r.register_cast("is_admin", CastType::Boolean);
1128
1129 r.register_mutator(Box::new(ClosureMutator::new("email", |v| match v {
1131 Value::String(s) => Value::String(s.to_lowercase()),
1132 other => other,
1133 })));
1134
1135 r.register_accessor(Box::new(ClosureAccessor::new(
1137 "full_name",
1138 |v| v, )));
1140
1141 r.register_cast("settings", CastType::Json);
1143
1144 r.register_cast("created_at", CastType::DateTime);
1146
1147 let v = r.read("is_admin", Value::I64(1));
1149 assert_eq!(v, Value::Bool(true));
1150
1151 let v = r.write("email", Value::String("Alice@Example.COM".to_string()));
1153 assert_eq!(v, Value::String("alice@example.com".to_string()));
1154
1155 let v = r.read("settings", Value::String(r#"{"theme":"dark"}"#.to_string()));
1157 assert!(matches!(v, Value::Json(_)));
1158
1159 assert_eq!(r.accessor_count(), 1);
1160 assert_eq!(r.mutator_count(), 1);
1161 assert_eq!(r.cast_count(), 3);
1162 }
1163
1164 #[test]
1167 fn test_default_is_empty() {
1168 let r = AccessorRegistry::default();
1169 assert_eq!(r.accessor_count(), 0);
1170 assert_eq!(r.mutator_count(), 0);
1171 assert_eq!(r.cast_count(), 0);
1172 }
1173}