Skip to main content

drasi_core/models/
element.rs

1// Copyright 2024 The Drasi Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::{
16    fmt::{Display, Formatter},
17    sync::Arc,
18};
19
20use crate::evaluation::variable_value::VariableValue;
21
22use super::{ElementPropertyMap, ElementValue};
23
24#[derive(Debug, Clone, Hash, PartialEq, Eq)]
25pub struct ElementReference {
26    pub source_id: Arc<str>,
27    pub element_id: Arc<str>,
28}
29
30impl ElementReference {
31    pub fn new(source_id: &str, element_id: &str) -> Self {
32        ElementReference {
33            source_id: Arc::from(source_id),
34            element_id: Arc::from(element_id),
35        }
36    }
37}
38
39impl Display for ElementReference {
40    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
41        write!(f, "{}:{}", self.source_id, self.element_id)
42    }
43}
44
45/// Timestamp type used for elements, measured in milliseconds since UNIX epoch.
46pub type ElementTimestamp = u64;
47
48#[derive(Debug, Clone, Hash, PartialEq, Eq)]
49pub struct ElementMetadata {
50    pub reference: ElementReference,
51    pub labels: Arc<[Arc<str>]>,
52
53    /// The effective time from which this element is valid. Measured in milliseconds since UNIX epoch.
54    pub effective_from: ElementTimestamp,
55}
56
57impl Display for ElementMetadata {
58    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
59        write!(
60            f,
61            "({}, [{}], {})",
62            self.reference,
63            self.labels.join(","),
64            self.effective_from
65        )
66    }
67}
68
69#[derive(Debug, Clone, Hash, Eq, PartialEq)]
70pub enum Element {
71    // Incoming changes get turned into an Element
72    Node {
73        metadata: ElementMetadata,
74        properties: ElementPropertyMap,
75    },
76    Relation {
77        metadata: ElementMetadata,
78        in_node: ElementReference,
79        out_node: ElementReference,
80        properties: ElementPropertyMap,
81    },
82}
83
84impl Element {
85    pub fn get_reference(&self) -> &ElementReference {
86        match self {
87            Element::Node { metadata, .. } => &metadata.reference,
88            Element::Relation { metadata, .. } => &metadata.reference,
89        }
90    }
91
92    pub fn get_effective_from(&self) -> ElementTimestamp {
93        match self {
94            Element::Node { metadata, .. } => metadata.effective_from,
95            Element::Relation { metadata, .. } => metadata.effective_from,
96        }
97    }
98
99    pub fn get_metadata(&self) -> &ElementMetadata {
100        match self {
101            Element::Node { metadata, .. } => metadata,
102            Element::Relation { metadata, .. } => metadata,
103        }
104    }
105
106    pub fn get_property(&self, name: &str) -> &ElementValue {
107        let props = match self {
108            Element::Node { properties, .. } => properties,
109            Element::Relation { properties, .. } => properties,
110        };
111        &props[name]
112    }
113
114    pub fn get_properties(&self) -> &ElementPropertyMap {
115        match self {
116            Element::Node { properties, .. } => properties,
117            Element::Relation { properties, .. } => properties,
118        }
119    }
120
121    pub fn merge_missing_properties(&mut self, other: &Element) {
122        match (self, other) {
123            (
124                Element::Node {
125                    properties,
126                    metadata,
127                },
128                Element::Node {
129                    properties: other_properties,
130                    metadata: other_metadata,
131                },
132            ) => {
133                assert_eq!(metadata.reference, other_metadata.reference);
134                properties.merge(other_properties);
135            }
136            (
137                Element::Relation {
138                    in_node: _,
139                    out_node: _,
140                    properties,
141                    metadata,
142                },
143                Element::Relation {
144                    in_node: _other_in_node,
145                    out_node: _other_out_node,
146                    properties: other_properties,
147                    metadata: other_metadata,
148                },
149            ) => {
150                assert_eq!(metadata.reference, other_metadata.reference);
151                properties.merge(other_properties);
152            }
153            _ => panic!("Cannot merge different element types"),
154        }
155    }
156
157    pub fn to_expression_variable(&self) -> VariableValue {
158        VariableValue::Element(Arc::new(self.clone()))
159    }
160
161    pub fn update_effective_time(&mut self, timestamp: ElementTimestamp) {
162        match self {
163            Element::Node { metadata, .. } => metadata.effective_from = timestamp,
164            Element::Relation { metadata, .. } => metadata.effective_from = timestamp,
165        }
166    }
167}
168
169impl From<&Element> for serde_json::Value {
170    fn from(val: &Element) -> Self {
171        match val {
172            Element::Node {
173                metadata,
174                properties,
175            } => {
176                let mut properties: serde_json::Map<String, serde_json::Value> = properties.into();
177
178                properties.insert(
179                    "$metadata".to_string(),
180                    serde_json::Value::String(metadata.to_string()),
181                );
182
183                serde_json::Value::Object(properties)
184            }
185            Element::Relation {
186                metadata,
187                in_node,
188                out_node,
189                properties,
190            } => {
191                let mut properties: serde_json::Map<String, serde_json::Value> = properties.into();
192
193                properties.insert(
194                    "$metadata".to_string(),
195                    serde_json::Value::String(metadata.to_string()),
196                );
197
198                properties.insert(
199                    "$in_node".to_string(),
200                    serde_json::Value::String(in_node.to_string()),
201                );
202                properties.insert(
203                    "$out_node".to_string(),
204                    serde_json::Value::String(out_node.to_string()),
205                );
206
207                serde_json::Value::Object(properties)
208            }
209        }
210    }
211}