Skip to main content

graphrecords_core/graphrecord/
attributes.rs

1use crate::{
2    GraphRecord,
3    errors::{GraphRecordError, GraphRecordResult},
4    prelude::{
5        Attributes, EdgeIndex, GraphRecordAttribute, GraphRecordValue, Group, NodeIndex, SchemaType,
6    },
7};
8
9macro_rules! impl_attributes_mut {
10    (
11        $struct_name:ident,
12        $index_type:ty,
13        $index_field:ident,
14        $entity:literal,
15        $contains_fn:ident,
16        $groups_of_fn:ident,
17        $get_attributes_fn:ident,
18        $get_attributes_mut_fn:ident,
19        $schema_update_fn:ident,
20        $schema_validate_fn:ident
21    ) => {
22        pub struct $struct_name<'a> {
23            $index_field: &'a $index_type,
24            graphrecord: &'a mut GraphRecord,
25        }
26
27        impl<'a> $struct_name<'a> {
28            pub(crate) fn new(
29                $index_field: &'a $index_type,
30                graphrecord: &'a mut GraphRecord,
31            ) -> GraphRecordResult<Self> {
32                if !graphrecord.$contains_fn($index_field) {
33                    return Err(GraphRecordError::IndexError(format!(
34                        concat!("Cannot find ", $entity, " with index {}"),
35                        $index_field
36                    )));
37                }
38
39                Ok(Self {
40                    $index_field,
41                    graphrecord,
42                })
43            }
44
45            fn get_groups(&self) -> Vec<Group> {
46                self.graphrecord
47                    .$groups_of_fn(self.$index_field)
48                    .expect(concat!($entity, " must exist."))
49                    .cloned()
50                    .collect()
51            }
52
53            fn handle_schema(
54                &mut self,
55                attributes: &Attributes,
56                groups: &[Group],
57            ) -> GraphRecordResult<()> {
58                let schema = &mut self.graphrecord.schema;
59
60                match schema.schema_type() {
61                    SchemaType::Inferred => {
62                        if groups.is_empty() {
63                            schema.$schema_update_fn(attributes, None, false);
64                        } else {
65                            for group in groups {
66                                schema.$schema_update_fn(attributes, Some(group), false);
67                            }
68                        }
69                    }
70                    SchemaType::Provided => {
71                        if groups.is_empty() {
72                            schema.$schema_validate_fn(self.$index_field, attributes, None)?;
73                        } else {
74                            for group in groups {
75                                schema.$schema_validate_fn(
76                                    self.$index_field,
77                                    attributes,
78                                    Some(group),
79                                )?;
80                            }
81                        }
82                    }
83                }
84
85                Ok(())
86            }
87
88            fn set_attributes(&mut self, attributes: Attributes) {
89                *self
90                    .graphrecord
91                    .graph
92                    .$get_attributes_mut_fn(self.$index_field)
93                    .expect(concat!($entity, " must exist.")) = attributes;
94            }
95
96            pub fn replace_attributes(&mut self, attributes: Attributes) -> GraphRecordResult<()> {
97                let groups = self.get_groups();
98                self.handle_schema(&attributes, &groups)?;
99                self.set_attributes(attributes);
100                Ok(())
101            }
102
103            pub fn update_attribute(
104                &mut self,
105                attribute: &GraphRecordAttribute,
106                value: GraphRecordValue,
107            ) -> GraphRecordResult<()> {
108                let groups = self.get_groups();
109
110                let mut attributes = self
111                    .graphrecord
112                    .$get_attributes_fn(self.$index_field)
113                    .expect(concat!($entity, " must exist."))
114                    .clone();
115                attributes
116                    .entry(attribute.clone())
117                    .and_modify(|v| *v = value.clone())
118                    .or_insert(value);
119
120                self.handle_schema(&attributes, &groups)?;
121                self.set_attributes(attributes);
122                Ok(())
123            }
124
125            pub fn remove_attribute(
126                &mut self,
127                attribute: &GraphRecordAttribute,
128            ) -> GraphRecordResult<GraphRecordValue> {
129                let groups = self.get_groups();
130
131                let mut attributes = self
132                    .graphrecord
133                    .$get_attributes_fn(self.$index_field)
134                    .expect(concat!($entity, " must exist."))
135                    .clone();
136                let removed_value = attributes.remove(attribute);
137
138                let Some(removed_value) = removed_value else {
139                    return Err(GraphRecordError::KeyError(format!(
140                        concat!("Attribute {} does not exist on ", $entity, " {}"),
141                        attribute, self.$index_field
142                    )));
143                };
144
145                self.handle_schema(&attributes, &groups)?;
146                self.set_attributes(attributes);
147                Ok(removed_value)
148            }
149        }
150    };
151}
152
153impl_attributes_mut!(
154    NodeAttributesMut,
155    NodeIndex,
156    node_index,
157    "node",
158    contains_node,
159    groups_of_node,
160    node_attributes,
161    node_attributes_mut,
162    update_node,
163    validate_node
164);
165
166impl_attributes_mut!(
167    EdgeAttributesMut,
168    EdgeIndex,
169    edge_index,
170    "edge",
171    contains_edge,
172    groups_of_edge,
173    edge_attributes,
174    edge_attributes_mut,
175    update_edge,
176    validate_edge
177);