raphtory_api/core/entities/properties/
props.rs

1use std::{ops::Deref, sync::Arc};
2
3use parking_lot::RwLock;
4use serde::{Deserialize, Serialize};
5
6use crate::core::{
7    storage::{
8        arc_str::ArcStr,
9        dict_mapper::{DictMapper, MaybeNew},
10        locked_vec::ArcReadLockedVec,
11    },
12    PropType,
13};
14
15use super::PropError;
16
17#[derive(Serialize, Deserialize, Debug)]
18pub struct Meta {
19    meta_prop_temporal: PropMapper,
20    meta_prop_constant: PropMapper,
21    meta_layer: DictMapper,
22    meta_node_type: DictMapper,
23}
24
25impl Default for Meta {
26    fn default() -> Self {
27        Self::new()
28    }
29}
30
31impl Meta {
32    pub fn set_const_prop_meta(&mut self, meta: PropMapper) {
33        self.meta_prop_constant = meta;
34    }
35    pub fn set_temporal_prop_meta(&mut self, meta: PropMapper) {
36        self.meta_prop_temporal = meta;
37    }
38    pub fn const_prop_meta(&self) -> &PropMapper {
39        &self.meta_prop_constant
40    }
41
42    pub fn temporal_prop_meta(&self) -> &PropMapper {
43        &self.meta_prop_temporal
44    }
45
46    pub fn layer_meta(&self) -> &DictMapper {
47        &self.meta_layer
48    }
49
50    pub fn node_type_meta(&self) -> &DictMapper {
51        &self.meta_node_type
52    }
53
54    pub fn new() -> Self {
55        let meta_layer = DictMapper::default();
56        meta_layer.get_or_create_id("_default");
57        let meta_node_type = DictMapper::default();
58        meta_node_type.get_or_create_id("_default");
59        Self {
60            meta_prop_temporal: PropMapper::default(),
61            meta_prop_constant: PropMapper::default(),
62            meta_layer,     // layer 0 is the default layer
63            meta_node_type, // type 0 is the default type for a node
64        }
65    }
66
67    #[inline]
68    pub fn resolve_prop_id(
69        &self,
70        prop: &str,
71        dtype: PropType,
72        is_static: bool,
73    ) -> Result<MaybeNew<usize>, PropError> {
74        if is_static {
75            self.meta_prop_constant
76                .get_or_create_and_validate(prop, dtype)
77        } else {
78            self.meta_prop_temporal
79                .get_or_create_and_validate(prop, dtype)
80        }
81    }
82
83    #[inline]
84    pub fn get_prop_id(&self, name: &str, is_static: bool) -> Option<usize> {
85        if is_static {
86            self.meta_prop_constant.get_id(name)
87        } else {
88            self.meta_prop_temporal.get_id(name)
89        }
90    }
91
92    #[inline]
93    pub fn get_or_create_layer_id(&self, name: &str) -> MaybeNew<usize> {
94        self.meta_layer.get_or_create_id(name)
95    }
96
97    #[inline]
98    pub fn get_default_node_type_id(&self) -> usize {
99        0usize
100    }
101
102    #[inline]
103    pub fn get_or_create_node_type_id(&self, node_type: &str) -> MaybeNew<usize> {
104        self.meta_node_type.get_or_create_id(node_type)
105    }
106
107    #[inline]
108    pub fn get_layer_id(&self, name: &str) -> Option<usize> {
109        self.meta_layer.get_id(name)
110    }
111
112    #[inline]
113    pub fn get_node_type_id(&self, node_type: &str) -> Option<usize> {
114        self.meta_node_type.get_id(node_type)
115    }
116
117    pub fn get_layer_name_by_id(&self, id: usize) -> ArcStr {
118        self.meta_layer.get_name(id)
119    }
120
121    pub fn get_node_type_name_by_id(&self, id: usize) -> Option<ArcStr> {
122        if id == 0 {
123            None
124        } else {
125            Some(self.meta_node_type.get_name(id))
126        }
127    }
128
129    pub fn get_all_layers(&self) -> Vec<usize> {
130        self.meta_layer.get_values()
131    }
132
133    pub fn get_all_node_types(&self) -> Vec<ArcStr> {
134        self.meta_node_type
135            .get_keys()
136            .iter()
137            .filter_map(|key| {
138                if key != "_default" {
139                    Some(key.clone())
140                } else {
141                    None
142                }
143            })
144            .collect()
145    }
146
147    pub fn get_all_property_names(&self, is_static: bool) -> ArcReadLockedVec<ArcStr> {
148        if is_static {
149            self.meta_prop_constant.get_keys()
150        } else {
151            self.meta_prop_temporal.get_keys()
152        }
153    }
154
155    pub fn get_prop_name(&self, prop_id: usize, is_static: bool) -> ArcStr {
156        if is_static {
157            self.meta_prop_constant.get_name(prop_id)
158        } else {
159            self.meta_prop_temporal.get_name(prop_id)
160        }
161    }
162}
163
164#[derive(Default, Debug, Serialize, Deserialize)]
165pub struct PropMapper {
166    id_mapper: DictMapper,
167    dtypes: Arc<RwLock<Vec<PropType>>>,
168}
169
170impl Deref for PropMapper {
171    type Target = DictMapper;
172
173    #[inline]
174    fn deref(&self) -> &Self::Target {
175        &self.id_mapper
176    }
177}
178
179impl PropMapper {
180    pub fn deep_clone(&self) -> Self {
181        let dtypes = self.dtypes.read().clone();
182        Self {
183            id_mapper: self.id_mapper.deep_clone(),
184            dtypes: Arc::new(RwLock::new(dtypes)),
185        }
186    }
187
188    pub fn get_and_validate(
189        &self,
190        prop: &str,
191        dtype: PropType,
192    ) -> Result<Option<usize>, PropError> {
193        match self.get_id(prop) {
194            Some(id) => {
195                let existing_dtype = self
196                    .get_dtype(id)
197                    .expect("Existing id should always have a dtype");
198                if existing_dtype == dtype {
199                    Ok(Some(id))
200                } else {
201                    Err(PropError::PropertyTypeError {
202                        name: prop.to_string(),
203                        expected: existing_dtype,
204                        actual: dtype,
205                    })
206                }
207            }
208            None => Ok(None),
209        }
210    }
211    pub fn get_or_create_and_validate(
212        &self,
213        prop: &str,
214        dtype: PropType,
215    ) -> Result<MaybeNew<usize>, PropError> {
216        let wrapped_id = self.id_mapper.get_or_create_id(prop);
217        let id = wrapped_id.inner();
218        let dtype_read = self.dtypes.read_recursive();
219        if let Some(old_type) = dtype_read.get(id) {
220            if !matches!(old_type, PropType::Empty) {
221                return if *old_type == dtype {
222                    Ok(wrapped_id)
223                } else {
224                    Err(PropError::PropertyTypeError {
225                        name: prop.to_owned(),
226                        expected: *old_type,
227                        actual: dtype,
228                    })
229                };
230            }
231        }
232        drop(dtype_read); // drop the read lock and wait for write lock as type did not exist yet
233        let mut dtype_write = self.dtypes.write();
234        match dtype_write.get(id) {
235            Some(&old_type) => {
236                if matches!(old_type, PropType::Empty) {
237                    // vector already resized but this id is not filled yet, set the dtype and return id
238                    dtype_write[id] = dtype;
239                    Ok(wrapped_id)
240                } else {
241                    // already filled because a different thread won the race for this id, check the type matches
242                    if old_type == dtype {
243                        Ok(wrapped_id)
244                    } else {
245                        Err(PropError::PropertyTypeError {
246                            name: prop.to_owned(),
247                            expected: old_type,
248                            actual: dtype,
249                        })
250                    }
251                }
252            }
253            None => {
254                // vector not resized yet, resize it and set the dtype and return id
255                dtype_write.resize(id + 1, PropType::Empty);
256                dtype_write[id] = dtype;
257                Ok(wrapped_id)
258            }
259        }
260    }
261
262    pub fn set_id_and_dtype(&self, key: impl Into<ArcStr>, id: usize, dtype: PropType) {
263        let mut dtypes = self.dtypes.write();
264        self.set_id(key, id);
265        if dtypes.len() <= id {
266            dtypes.resize(id + 1, PropType::Empty);
267        }
268        dtypes[id] = dtype;
269    }
270
271    pub fn get_dtype(&self, prop_id: usize) -> Option<PropType> {
272        self.dtypes.read_recursive().get(prop_id).copied()
273    }
274
275    pub fn dtypes(&self) -> impl Deref<Target = Vec<PropType>> + '_ {
276        self.dtypes.read_recursive()
277    }
278}