icydb_schema/node/
item.rs1use crate::prelude::*;
2use std::ops::Not;
3
4#[derive(Clone, Debug, Serialize)]
12pub struct Item {
13 target: ItemTarget,
14
15 #[serde(skip_serializing_if = "Option::is_none")]
16 relation: Option<&'static str>,
17
18 #[serde(skip_serializing_if = "Option::is_none")]
19 scale: Option<u32>,
20
21 #[serde(skip_serializing_if = "Option::is_none")]
22 max_len: Option<u32>,
23
24 #[serde(skip_serializing_if = "Option::is_none")]
25 max_bytes: Option<u32>,
26
27 #[serde(skip_serializing_if = "<[_]>::is_empty")]
28 validators: &'static [TypeValidator],
29
30 #[serde(skip_serializing_if = "<[_]>::is_empty")]
31 sanitizers: &'static [TypeSanitizer],
32
33 #[serde(skip_serializing_if = "Not::not")]
34 indirect: bool,
35}
36
37impl Item {
38 #[must_use]
39 #[expect(
40 clippy::too_many_arguments,
41 reason = "schema item construction keeps generated scalar, relation, and validation metadata explicit"
42 )]
43 pub const fn new(
44 target: ItemTarget,
45 relation: Option<&'static str>,
46 scale: Option<u32>,
47 max_len: Option<u32>,
48 max_bytes: Option<u32>,
49 validators: &'static [TypeValidator],
50 sanitizers: &'static [TypeSanitizer],
51 indirect: bool,
52 ) -> Self {
53 Self {
54 target,
55 relation,
56 scale,
57 max_len,
58 max_bytes,
59 validators,
60 sanitizers,
61 indirect,
62 }
63 }
64
65 #[must_use]
66 pub const fn target(&self) -> &ItemTarget {
67 &self.target
68 }
69
70 #[must_use]
71 pub const fn relation(&self) -> Option<&'static str> {
72 self.relation
73 }
74
75 #[must_use]
76 pub const fn scale(&self) -> Option<u32> {
77 self.scale
78 }
79
80 #[must_use]
81 pub const fn max_len(&self) -> Option<u32> {
82 self.max_len
83 }
84
85 #[must_use]
86 pub const fn max_bytes(&self) -> Option<u32> {
87 self.max_bytes
88 }
89
90 #[must_use]
91 pub const fn validators(&self) -> &'static [TypeValidator] {
92 self.validators
93 }
94
95 #[must_use]
96 pub const fn sanitizers(&self) -> &'static [TypeSanitizer] {
97 self.sanitizers
98 }
99
100 #[must_use]
101 pub const fn indirect(&self) -> bool {
102 self.indirect
103 }
104
105 #[must_use]
106 pub const fn is_relation(&self) -> bool {
107 self.relation().is_some()
108 }
109}
110
111impl ValidateNode for Item {
112 fn validate(&self) -> Result<(), ErrorTree> {
113 let mut errs = ErrorTree::new();
114 let schema = schema_read();
115
116 match self.target() {
118 ItemTarget::Is(path) => {
119 if schema.check_node_as::<Entity>(path).is_ok() {
121 err!(errs, "a non-relation Item cannot reference an Entity");
122 }
123 }
124
125 ItemTarget::Primitive(_) => {}
126 }
127
128 if let Some(relation) = self.relation() {
130 match schema.cast_node::<Entity>(relation) {
132 Ok(entity) => {
133 if let Some(primary_field) = entity.get_pk_field() {
135 let relation_target = primary_field.value().item().target();
136
137 let relation_scale = primary_field.value().item().scale();
139 let relation_max_len = primary_field.value().item().max_len();
140 let relation_max_bytes = primary_field.value().item().max_bytes();
141 if self.target() != relation_target
142 || self.scale() != relation_scale
143 || self.max_len() != relation_max_len
144 || self.max_bytes() != relation_max_bytes
145 {
146 err!(
147 errs,
148 "relation target type mismatch: expected ({:?}, scale={:?}, max_len={:?}, max_bytes={:?}), found ({:?}, scale={:?}, max_len={:?}, max_bytes={:?})",
149 relation_target,
150 relation_scale,
151 relation_max_len,
152 relation_max_bytes,
153 self.target(),
154 self.scale(),
155 self.max_len(),
156 self.max_bytes()
157 );
158 }
159 } else {
160 err!(
161 errs,
162 "relation entity '{relation}' missing primary key field '{0}'",
163 entity.primary_key().field()
164 );
165 }
166 }
167 Err(_) => {
168 err!(errs, "relation entity '{relation}' not found");
169 }
170 }
171 }
172
173 errs.result()
174 }
175}
176
177impl VisitableNode for Item {
178 fn drive<V: Visitor>(&self, v: &mut V) {
179 for node in self.validators() {
180 node.accept(v);
181 }
182 }
183}
184
185#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
193pub enum ItemTarget {
194 Is(&'static str),
195 Primitive(Primitive),
196}