icydb_schema/node/
field.rs1use crate::prelude::*;
2use canic_utils::case::{Case, Casing};
3
4#[derive(Clone, Debug, Serialize)]
9pub struct FieldList {
10 pub fields: &'static [Field],
11}
12
13impl FieldList {
14 #[must_use]
16 pub fn get(&self, ident: &str) -> Option<&Field> {
17 self.fields.iter().find(|f| f.ident == ident)
18 }
19}
20
21impl ValidateNode for FieldList {}
22
23impl VisitableNode for FieldList {
24 fn drive<V: Visitor>(&self, v: &mut V) {
25 for node in self.fields {
26 node.accept(v);
27 }
28 }
29}
30
31#[derive(Clone, Debug, Serialize)]
36pub struct Field {
37 pub ident: &'static str,
38 pub value: Value,
39
40 #[serde(default, skip_serializing_if = "Option::is_none")]
41 pub default: Option<Arg>,
42}
43
44impl ValidateNode for Field {
45 fn validate(&self) -> Result<(), ErrorTree> {
46 let mut errs = ErrorTree::new();
47
48 errs.add_result(validate_ident(self.ident));
50 if let Err(msg) = crate::build::validate::validate_field_name_len(self.ident) {
51 err!(errs, "{msg}");
52 }
53
54 if !self.ident.is_case(Case::Snake) {
56 err!(errs, "field ident '{}' must be snake_case", self.ident);
57 }
58
59 if self.value.item.is_relation() {
61 let ident = self.ident;
62 match self.value.cardinality {
63 Cardinality::One | Cardinality::Opt if !ident.ends_with("id") => {
64 err!(
65 errs,
66 "one or optional relationship '{ident}' should end with 'id'"
67 );
68 }
69 Cardinality::Many if !ident.ends_with("ids") => {
70 err!(errs, "many relationship '{ident}' should end with 'ids'");
71 }
72
73 _ => {}
74 }
75 }
76
77 errs.result()
78 }
79}
80
81impl VisitableNode for Field {
82 fn route_key(&self) -> String {
83 self.ident.to_string()
84 }
85
86 fn drive<V: Visitor>(&self, v: &mut V) {
87 self.value.accept(v);
88 if let Some(node) = &self.default {
89 node.accept(v);
90 }
91 }
92}