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
45pub type ElementTimestamp = u64;
46
47#[derive(Debug, Clone, Hash, PartialEq, Eq)]
48pub struct ElementMetadata {
49    pub reference: ElementReference,
50    pub labels: Arc<[Arc<str>]>,
51    pub effective_from: ElementTimestamp,
52}
53
54impl Display for ElementMetadata {
55    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
56        write!(
57            f,
58            "({}, [{}], {})",
59            self.reference,
60            self.labels.join(","),
61            self.effective_from
62        )
63    }
64}
65
66#[derive(Debug, Clone, Hash, Eq, PartialEq)]
67pub enum Element {
68    // Incoming changes get turned into an Element
69    Node {
70        metadata: ElementMetadata,
71        properties: ElementPropertyMap,
72    },
73    Relation {
74        metadata: ElementMetadata,
75        in_node: ElementReference,
76        out_node: ElementReference,
77        properties: ElementPropertyMap,
78    },
79}
80
81impl Element {
82    pub fn get_reference(&self) -> &ElementReference {
83        match self {
84            Element::Node { metadata, .. } => &metadata.reference,
85            Element::Relation { metadata, .. } => &metadata.reference,
86        }
87    }
88
89    pub fn get_effective_from(&self) -> ElementTimestamp {
90        match self {
91            Element::Node { metadata, .. } => metadata.effective_from,
92            Element::Relation { metadata, .. } => metadata.effective_from,
93        }
94    }
95
96    pub fn get_metadata(&self) -> &ElementMetadata {
97        match self {
98            Element::Node { metadata, .. } => metadata,
99            Element::Relation { metadata, .. } => metadata,
100        }
101    }
102
103    pub fn get_property(&self, name: &str) -> &ElementValue {
104        let props = match self {
105            Element::Node { properties, .. } => properties,
106            Element::Relation { properties, .. } => properties,
107        };
108        &props[name]
109    }
110
111    pub fn get_properties(&self) -> &ElementPropertyMap {
112        match self {
113            Element::Node { properties, .. } => properties,
114            Element::Relation { properties, .. } => properties,
115        }
116    }
117
118    pub fn merge_missing_properties(&mut self, other: &Element) {
119        match (self, other) {
120            (
121                Element::Node {
122                    properties,
123                    metadata,
124                },
125                Element::Node {
126                    properties: other_properties,
127                    metadata: other_metadata,
128                },
129            ) => {
130                assert_eq!(metadata.reference, other_metadata.reference);
131                properties.merge(other_properties);
132            }
133            (
134                Element::Relation {
135                    in_node: _,
136                    out_node: _,
137                    properties,
138                    metadata,
139                },
140                Element::Relation {
141                    in_node: _other_in_node,
142                    out_node: _other_out_node,
143                    properties: other_properties,
144                    metadata: other_metadata,
145                },
146            ) => {
147                assert_eq!(metadata.reference, other_metadata.reference);
148                properties.merge(other_properties);
149            }
150            _ => panic!("Cannot merge different element types"),
151        }
152    }
153
154    pub fn to_expression_variable(&self) -> VariableValue {
155        VariableValue::Element(Arc::new(self.clone()))
156    }
157
158    pub fn update_effective_time(&mut self, timestamp: ElementTimestamp) {
159        match self {
160            Element::Node { metadata, .. } => metadata.effective_from = timestamp,
161            Element::Relation { metadata, .. } => metadata.effective_from = timestamp,
162        }
163    }
164}
165
166impl From<&Element> for serde_json::Value {
167    fn from(val: &Element) -> Self {
168        match val {
169            Element::Node {
170                metadata,
171                properties,
172            } => {
173                let mut properties: serde_json::Map<String, serde_json::Value> = properties.into();
174
175                properties.insert(
176                    "$metadata".to_string(),
177                    serde_json::Value::String(metadata.to_string()),
178                );
179
180                serde_json::Value::Object(properties)
181            }
182            Element::Relation {
183                metadata,
184                in_node,
185                out_node,
186                properties,
187            } => {
188                let mut properties: serde_json::Map<String, serde_json::Value> = properties.into();
189
190                properties.insert(
191                    "$metadata".to_string(),
192                    serde_json::Value::String(metadata.to_string()),
193                );
194
195                properties.insert(
196                    "$in_node".to_string(),
197                    serde_json::Value::String(in_node.to_string()),
198                );
199                properties.insert(
200                    "$out_node".to_string(),
201                    serde_json::Value::String(out_node.to_string()),
202                );
203
204                serde_json::Value::Object(properties)
205            }
206        }
207    }
208}