icydb_schema/node/
item.rs1use crate::prelude::*;
2use std::ops::Not;
3
4#[derive(Clone, Debug, Serialize)]
9pub struct Item {
10 pub target: ItemTarget,
11
12 #[serde(default, skip_serializing_if = "Option::is_none")]
13 pub relation: Option<&'static str>,
14
15 #[serde(default, skip_serializing_if = "Option::is_none")]
16 pub external: Option<&'static str>,
17
18 #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
19 pub validators: &'static [TypeValidator],
20
21 #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
22 pub sanitizers: &'static [TypeSanitizer],
23
24 #[serde(default, skip_serializing_if = "Not::not")]
25 pub indirect: bool,
26}
27
28impl Item {
29 #[must_use]
30 pub const fn is_relation(&self) -> bool {
31 self.relation.is_some()
32 }
33}
34
35impl ValidateNode for Item {
36 fn validate(&self) -> Result<(), ErrorTree> {
37 let mut errs = ErrorTree::new();
38 let schema = schema_read();
39
40 if self.relation.is_some() && self.external.is_some() {
42 err!(errs, "an Item cannot specify both rel and ext");
43 }
44
45 match &self.target {
47 ItemTarget::Is(path) => {
48 if schema.check_node_as::<Entity>(path).is_ok() {
50 err!(errs, "a non-relation Item cannot reference an Entity");
51 }
52 }
53
54 ItemTarget::Primitive(_) => {}
55 }
56
57 if let Some(relation) = &self.relation {
59 match schema.cast_node::<Entity>(relation) {
61 Ok(entity) => {
62 if let Some(primary_field) = entity.get_pk_field() {
64 let relation_target = &primary_field.value.item.target;
65
66 if &self.target != relation_target {
68 err!(
69 errs,
70 "relation target type mismatch: expected {:?}, found {:?}",
71 relation_target,
72 self.target
73 );
74 }
75 } else {
76 err!(
77 errs,
78 "relation entity '{relation}' missing primary key field '{0}'",
79 entity.primary_key
80 );
81 }
82 }
83 Err(_) => {
84 err!(errs, "relation entity '{relation}' not found");
85 }
86 }
87 }
88
89 errs.result()
90 }
91}
92
93impl VisitableNode for Item {
94 fn drive<V: Visitor>(&self, v: &mut V) {
95 for node in self.validators {
96 node.accept(v);
97 }
98 }
99}
100
101#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
106pub enum ItemTarget {
107 Is(&'static str),
108 Primitive(Primitive),
109}