tablo_core/schema/
options.rs1pub trait Options {
30 fn options() -> Vec<(String, String)>;
32
33 fn label_of(value: &str) -> String {
36 Self::options()
37 .into_iter()
38 .find(|(stored, _)| stored == value)
39 .map_or_else(|| value.to_string(), |(_, label)| label)
40 }
41}
42
43#[cfg(test)]
44mod tests {
45 use super::Options;
46 use crate::Column as _;
47
48 #[derive(Debug, Clone, Copy, PartialEq, Eq, crate::Options)]
50 enum Status {
51 Draft,
52 #[option(label = "Live")]
53 Published,
54 #[option(value = "arch", label = "Archive")]
55 Archived,
56 }
57
58 #[test]
59 fn an_options_enum_shares_one_value_label_list() {
60 assert_eq!(
61 Status::options(),
62 vec![
63 ("draft".to_string(), "Draft".to_string()),
64 ("published".to_string(), "Live".to_string()),
65 ("arch".to_string(), "Archive".to_string()),
66 ]
67 );
68 assert_eq!(Status::Draft.value(), "draft");
69 assert_eq!(Status::Published.label(), "Live");
70 assert_eq!(Status::from_value("draft"), Some(Status::Draft));
71 assert_eq!(Status::from_value("arch"), Some(Status::Archived));
72 assert_eq!(Status::from_value("gone"), None);
73 assert_eq!(Status::label_of("published"), "Live");
74 assert_eq!(
75 Status::label_of("renamed"),
76 "renamed",
77 "a value no option stores reads as itself"
78 );
79 }
80
81 #[tokio::test]
82 async fn the_shared_list_feeds_a_choice_a_select_filter_and_a_column() {
83 let options = Status::options();
84 let schema = crate::Schema::new(
85 crate::Field::choice(StatusField::fields().status()).options(options.clone()),
86 );
87 let mut valid = std::collections::HashMap::new();
88 valid.insert("status".to_string(), "draft".to_string());
89 let cx = topcoat::context::CxTestBuilder::new().build();
90 let errors = schema.validate_async(&cx, &valid).await;
91 assert!(errors.is_empty(), "a shared option validates: {errors:?}");
92 let mut bogus = std::collections::HashMap::new();
93 bogus.insert("status".to_string(), "gone".to_string());
94 assert!(
95 !schema.validate_async(&cx, &bogus).await.is_empty(),
96 "an unlisted value fails"
97 );
98 let filter = crate::SelectFilter::new(StatusField::fields().status(), options.clone());
99 assert_eq!(filter.options(), options.as_slice());
100 let column = crate::TextColumn::new(crate::lens!(StatusField.status))
101 .format(|status| Status::label_of(status));
102 let row = StatusField {
103 id: uuid::Uuid::nil(),
104 status: "published".to_string(),
105 };
106 assert_eq!(column.text(&row), "Live");
107 }
108
109 #[derive(Debug, Clone, toasty::Model)]
110 struct StatusField {
111 #[key]
112 #[auto]
113 id: uuid::Uuid,
114 status: String,
115 }
116}