reactive_graph_graph/instances/relations/
relation_instance.rs

1use std::cmp::Ordering;
2use std::fmt::Display;
3use std::fmt::Formatter;
4use std::hash::Hash;
5use std::hash::Hasher;
6use std::ops::Deref;
7use std::ops::DerefMut;
8
9use const_format::formatcp;
10use dashmap::DashMap;
11use dashmap::iter::OwningIter;
12#[cfg(any(test, feature = "test"))]
13use default_test::DefaultTest;
14#[cfg(any(test, feature = "test"))]
15use rand::Rng;
16use schemars::JsonSchema;
17use schemars::Schema;
18use schemars::SchemaGenerator;
19use schemars::json_schema;
20use serde::Deserialize;
21use serde::Deserializer;
22use serde::Serialize;
23use serde::Serializer;
24use serde_json::Map;
25use serde_json::Value;
26use std::borrow::Cow;
27use typed_builder::TypedBuilder;
28use uuid::Uuid;
29
30use crate::AddExtensionError;
31use crate::ComponentTypeId;
32use crate::ComponentTypeIdContainer;
33use crate::ComponentTypeIds;
34use crate::Extension;
35use crate::ExtensionContainer;
36use crate::ExtensionTypeId;
37use crate::Extensions;
38use crate::JSON_SCHEMA_ID_URI_PREFIX;
39use crate::MutablePropertyInstanceSetter;
40use crate::NamespacedTypeGetter;
41use crate::PropertyInstanceGetter;
42use crate::PropertyInstances;
43use crate::RelationInstanceId;
44use crate::RelationInstanceTypeId;
45use crate::RelationTypeId;
46use crate::RelationTypeIds;
47use crate::RemoveExtensionError;
48use crate::TypeDefinition;
49use crate::TypeDefinitionGetter;
50use crate::UpdateExtensionError;
51use crate::instances::named::NamedInstanceContainer;
52#[cfg(any(test, feature = "test"))]
53use reactive_graph_utils_test::r_string;
54
55pub const JSON_SCHEMA_ID_RELATION_INSTANCE: &str = formatcp!("{}/relation-instance.schema.json", JSON_SCHEMA_ID_URI_PREFIX);
56
57/// Relation instances are edges from an outbound entity instance to an
58/// inbound entity instance.
59///
60/// The relation instance is of a relation type. The relation type defines
61/// the entity types of the outbound entity instance and the inbound entity
62/// instance. Furthermore, the relation type defines which properties
63/// (name, data type, socket type) a relation instance have to have.
64///
65/// In contrast to the relation type, the relation instance stores values/
66/// documents in its properties.
67#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, JsonSchema, TypedBuilder)]
68#[serde(tag = "$id", rename = "https://schema.reactive-graph.io/schema/json/relation-instance.schema.json")]
69#[schemars(
70    title = "RelationInstance",
71    rename = "RelationInstance",
72    deny_unknown_fields,
73    extend("$id" = JSON_SCHEMA_ID_RELATION_INSTANCE),
74    transform = add_json_schema_id_property
75)]
76pub struct RelationInstance {
77    /// The id of the outbound vertex.
78    pub outbound_id: Uuid,
79
80    /// The relation instance id is unique and consists of the relation type and an instance_id.
81    #[serde(flatten)]
82    #[builder(setter(into))]
83    pub ty: RelationInstanceTypeId,
84
85    /// The id of the inbound vertex.
86    pub inbound_id: Uuid,
87
88    /// The name of the relation instance.
89    #[serde(default = "String::new")]
90    #[builder(default, setter(into))]
91    pub name: String,
92
93    /// Textual description of the relation instance.
94    #[serde(default = "String::new")]
95    #[builder(default, setter(into))]
96    pub description: String,
97
98    /// The properties of then relation instance.
99    ///
100    /// Each property is represented by its name (String) and it's value. The value is
101    /// a representation of a JSON. Therefore, the value can be boolean, number, string,
102    /// array or an object. For more information about the data types please look at
103    /// <https://docs.serde.rs/serde_json/value/enum.Value.html>
104    #[serde(default = "PropertyInstances::new")]
105    #[builder(default, setter(into))]
106    pub properties: PropertyInstances,
107
108    /// The components of the entity instance.
109    #[serde(default = "ComponentTypeIds::new")]
110    #[builder(default, setter(into))]
111    pub components: ComponentTypeIds,
112
113    /// Relation instance specific extensions.
114    #[serde(default = "Extensions::new")]
115    #[builder(default, setter(into))]
116    pub extensions: Extensions,
117}
118
119impl RelationInstance {
120    /// Constructs a new relation instance with the given outbound_id, type, inbound_id and properties
121    pub fn new<T: Into<RelationInstanceTypeId>, P: Into<PropertyInstances>>(outbound_id: Uuid, ty: T, inbound_id: Uuid, properties: P) -> RelationInstance {
122        RelationInstance {
123            outbound_id,
124            ty: ty.into(),
125            inbound_id,
126            name: String::new(),
127            description: String::new(),
128            properties: properties.into(),
129            components: ComponentTypeIds::new(),
130            extensions: Extensions::new(),
131        }
132    }
133
134    /// Constructs a new relation instance with the given outbound_id, type, inbound_id and properties
135    pub fn new_from_type_unique_id<S: Into<String>, P: Into<PropertyInstances>>(
136        namespace: S,
137        outbound_id: Uuid,
138        type_name: S,
139        inbound_id: Uuid,
140        properties: P,
141    ) -> RelationInstance {
142        RelationInstance {
143            outbound_id,
144            ty: RelationInstanceTypeId::new_from_type_unique_id(namespace, type_name),
145            inbound_id,
146            name: String::new(),
147            description: String::new(),
148            properties: properties.into(),
149            components: ComponentTypeIds::new(),
150            extensions: Extensions::new(),
151        }
152    }
153
154    /// Constructs a new relation instance with the given outbound_id, type, inbound_id and properties
155    pub fn new_from_type_unique_for_instance_id<S: Into<String>, P: Into<PropertyInstances>>(
156        namespace: S,
157        outbound_id: Uuid,
158        type_name: S,
159        instance_id: S,
160        inbound_id: Uuid,
161        properties: P,
162    ) -> RelationInstance {
163        RelationInstance {
164            outbound_id,
165            ty: RelationInstanceTypeId::new_from_type_unique_for_instance_id(namespace, type_name, instance_id),
166            inbound_id,
167            name: String::new(),
168            description: String::new(),
169            properties: properties.into(),
170            components: ComponentTypeIds::new(),
171            extensions: Extensions::new(),
172        }
173    }
174
175    /// Constructs a new relation instance with the given outbound_id, type, inbound_id and properties
176    pub fn new_from_type_with_random_instance_id<S: Into<String>, P: Into<PropertyInstances>>(
177        namespace: S,
178        outbound_id: Uuid,
179        type_name: S,
180        inbound_id: Uuid,
181        properties: P,
182    ) -> RelationInstance {
183        RelationInstance {
184            outbound_id,
185            ty: RelationInstanceTypeId::new_from_type_with_random_instance_id(namespace, type_name),
186            inbound_id,
187            name: String::new(),
188            description: String::new(),
189            properties: properties.into(),
190            components: ComponentTypeIds::new(),
191            extensions: Extensions::new(),
192        }
193    }
194
195    /// Constructs a new relation instance with the given outbound_id, type, inbound_id but without properties
196    pub fn new_without_properties<T: Into<RelationInstanceTypeId>>(outbound_id: Uuid, ty: T, inbound_id: Uuid) -> RelationInstance {
197        RelationInstance {
198            outbound_id,
199            ty: ty.into(),
200            inbound_id,
201            name: String::new(),
202            description: String::new(),
203            properties: PropertyInstances::new(),
204            components: ComponentTypeIds::new(),
205            extensions: Extensions::new(),
206        }
207    }
208
209    /// Returns the relation instance id.
210    pub fn id(&self) -> RelationInstanceId {
211        RelationInstanceId::builder()
212            .outbound_id(self.outbound_id)
213            .ty(self.ty.clone())
214            .inbound_id(self.inbound_id)
215            .build()
216    }
217
218    /// Returns the inner relation type id.
219    pub fn relation_type_id(&self) -> RelationTypeId {
220        self.ty.relation_type_id()
221    }
222
223    /// Returns the relation instance type id.
224    pub fn instance_id(&self) -> String {
225        self.ty.instance_id()
226    }
227}
228
229impl NamedInstanceContainer for RelationInstance {
230    fn name(&self) -> String {
231        self.name.clone()
232    }
233
234    fn description(&self) -> String {
235        self.description.clone()
236    }
237}
238
239impl PropertyInstanceGetter for RelationInstance {
240    fn get<S: Into<String>>(&self, property_name: S) -> Option<Value> {
241        self.properties.get(property_name.into())
242    }
243
244    fn as_bool<S: Into<String>>(&self, property_name: S) -> Option<bool> {
245        self.properties.as_bool(property_name.into())
246    }
247
248    fn as_u64<S: Into<String>>(&self, property_name: S) -> Option<u64> {
249        self.properties.as_u64(property_name.into())
250    }
251
252    fn as_i64<S: Into<String>>(&self, property_name: S) -> Option<i64> {
253        self.properties.as_i64(property_name.into())
254    }
255
256    fn as_f64<S: Into<String>>(&self, property_name: S) -> Option<f64> {
257        self.properties.as_f64(property_name.into())
258    }
259
260    fn as_string<S: Into<String>>(&self, property_name: S) -> Option<String> {
261        self.properties.as_string(property_name.into())
262    }
263
264    fn as_array<S: Into<String>>(&self, property_name: S) -> Option<Vec<Value>> {
265        self.properties.as_array(property_name.into())
266    }
267
268    fn as_object<S: Into<String>>(&self, property_name: S) -> Option<Map<String, Value>> {
269        self.properties.as_object(property_name.into())
270    }
271}
272
273impl MutablePropertyInstanceSetter for RelationInstance {
274    fn set<S: Into<String>>(&mut self, property_name: S, value: Value) {
275        self.properties.set(property_name.into(), value);
276    }
277}
278
279impl ComponentTypeIdContainer for RelationInstance {
280    fn is_a(&self, ty: &ComponentTypeId) -> bool {
281        self.components.is_a(ty)
282    }
283
284    fn add_component<C: Into<ComponentTypeId>>(&self, ty: C) -> bool {
285        self.components.add_component(ty)
286    }
287
288    fn add_components<C: Into<ComponentTypeIds>>(&mut self, components_to_add: C) {
289        self.components.add_components(components_to_add)
290    }
291
292    fn remove_component(&self, ty: &ComponentTypeId) -> Option<ComponentTypeId> {
293        self.components.remove_component(ty)
294    }
295
296    fn remove_components<C: Into<ComponentTypeIds>>(&mut self, components_to_remove: C) {
297        self.components.remove_components(components_to_remove)
298    }
299}
300
301impl ExtensionContainer for RelationInstance {
302    fn has_own_extension(&self, ty: &ExtensionTypeId) -> bool {
303        self.extensions.has_own_extension(ty)
304    }
305
306    fn get_own_extension(&self, ty: &ExtensionTypeId) -> Option<Extension> {
307        self.extensions.get_own_extension(ty)
308    }
309
310    fn add_extension<E: Into<Extension>>(&self, extension: E) -> Result<ExtensionTypeId, AddExtensionError> {
311        self.extensions.add_extension(extension)
312    }
313
314    fn update_extension<T: Into<ExtensionTypeId>, E: Into<Extension>>(&self, ty: T, extension: E) -> Result<Extension, UpdateExtensionError> {
315        self.extensions.update_extension(ty, extension)
316    }
317
318    fn remove_extension<T: Into<ExtensionTypeId>>(&self, ty: T) -> Result<Extension, RemoveExtensionError> {
319        self.extensions.remove_extension(ty)
320    }
321
322    fn merge_extensions<E: Into<Extensions>>(&mut self, extensions_to_merge: E) {
323        self.extensions.merge_extensions(extensions_to_merge)
324    }
325}
326
327impl NamespacedTypeGetter for RelationInstance {
328    fn namespace(&self) -> String {
329        self.ty.namespace()
330    }
331
332    fn type_name(&self) -> String {
333        self.ty.type_name()
334    }
335}
336
337impl TypeDefinitionGetter for RelationInstance {
338    fn type_definition(&self) -> TypeDefinition {
339        self.ty.type_definition()
340    }
341}
342
343impl PartialEq<RelationInstanceId> for RelationInstance {
344    fn eq(&self, id: &RelationInstanceId) -> bool {
345        self.id() == *id
346    }
347}
348
349impl PartialOrd<Self> for RelationInstance {
350    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
351        Some(self.cmp(other))
352    }
353}
354
355impl Ord for RelationInstance {
356    fn cmp(&self, other: &Self) -> Ordering {
357        let id = self.id();
358        let other_id = other.id();
359        id.cmp(&other_id)
360    }
361}
362
363impl Display for RelationInstance {
364    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
365        write!(f, "{}", self.id())
366        // write!(f, "{}--[{}]-->{}", self.outbound_id, &self.ty, self.inbound_id)
367    }
368}
369
370#[derive(Clone, Debug, Default)]
371// #[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize, JsonSchema)]
372pub struct RelationInstances(DashMap<RelationInstanceId, RelationInstance>);
373
374impl RelationInstances {
375    pub fn new() -> Self {
376        RelationInstances(DashMap::new())
377    }
378
379    pub fn push<E: Into<RelationInstance>>(&self, relation_instance: E) {
380        let relation_instance = relation_instance.into();
381        self.0.insert(relation_instance.id(), relation_instance);
382    }
383
384    pub fn to_vec(&self) -> Vec<RelationInstance> {
385        let mut items: Vec<_> = self.iter().map(|item| item.value().clone()).collect();
386        items.sort();
387        items
388    }
389
390    // TODO: deduplicate?
391    pub fn get_type_ids(&self) -> RelationTypeIds {
392        self.iter().map(|r| r.relation_type_id()).collect()
393    }
394}
395
396impl Deref for RelationInstances {
397    type Target = DashMap<RelationInstanceId, RelationInstance>;
398
399    fn deref(&self) -> &Self::Target {
400        &self.0
401    }
402}
403
404impl DerefMut for RelationInstances {
405    fn deref_mut(&mut self) -> &mut Self::Target {
406        &mut self.0
407    }
408}
409
410impl IntoIterator for RelationInstances {
411    type Item = (RelationInstanceId, RelationInstance);
412    type IntoIter = OwningIter<RelationInstanceId, RelationInstance>;
413
414    fn into_iter(self) -> Self::IntoIter {
415        self.0.into_iter()
416    }
417}
418
419impl PartialEq for RelationInstances {
420    fn eq(&self, other: &Self) -> bool {
421        self.0.iter().all(|self_entity_instance| other.contains_key(&self_entity_instance.id()))
422            && other.iter().all(|other_entity_instance| self.contains_key(&other_entity_instance.id()))
423    }
424}
425
426impl Eq for RelationInstances {}
427
428impl Hash for RelationInstances {
429    fn hash<H: Hasher>(&self, state: &mut H) {
430        self.to_vec().hash(state);
431    }
432}
433
434impl Serialize for RelationInstances {
435    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
436    where
437        S: Serializer,
438    {
439        serializer.collect_seq(self.iter())
440    }
441}
442
443impl<'de> Deserialize<'de> for RelationInstances {
444    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
445    where
446        D: Deserializer<'de>,
447    {
448        Ok(Vec::<RelationInstance>::deserialize(deserializer)?.into())
449    }
450}
451
452impl JsonSchema for RelationInstances {
453    fn schema_name() -> Cow<'static, str> {
454        "RelationInstances".into()
455    }
456
457    fn json_schema(schema_generator: &mut SchemaGenerator) -> Schema {
458        let sub_schema: Schema = schema_generator.subschema_for::<RelationInstance>();
459        json_schema!({
460            "type": "array",
461            "items": sub_schema,
462            "description": "Relation Instances",
463        })
464    }
465}
466
467impl From<Vec<RelationInstance>> for RelationInstances {
468    fn from(relation_instances: Vec<RelationInstance>) -> Self {
469        Self(
470            relation_instances
471                .into_iter()
472                .map(|relation_instance| (relation_instance.id(), relation_instance))
473                .collect(),
474        )
475    }
476}
477
478impl From<RelationInstances> for Vec<RelationInstance> {
479    fn from(relation_instances: RelationInstances) -> Self {
480        relation_instances.to_vec()
481    }
482}
483
484impl From<&RelationInstances> for Vec<RelationInstance> {
485    fn from(relation_instances: &RelationInstances) -> Self {
486        relation_instances.0.iter().map(|relation_instance| relation_instance.clone()).collect()
487    }
488}
489
490impl From<DashMap<RelationInstanceId, RelationInstance>> for RelationInstances {
491    fn from(relation_instances: DashMap<RelationInstanceId, RelationInstance>) -> Self {
492        Self(relation_instances)
493    }
494}
495
496impl From<&DashMap<RelationInstanceId, RelationInstance>> for RelationInstances {
497    fn from(relation_instances: &DashMap<RelationInstanceId, RelationInstance>) -> Self {
498        Self(relation_instances.clone())
499    }
500}
501
502impl From<RelationInstances> for DashMap<RelationInstanceId, RelationInstance> {
503    fn from(relation_instances: RelationInstances) -> Self {
504        relation_instances.0
505    }
506}
507
508impl FromIterator<RelationInstance> for RelationInstances {
509    fn from_iter<I: IntoIterator<Item = RelationInstance>>(iter: I) -> Self {
510        let relation_instances = Self::new();
511        for relation_instance in iter {
512            relation_instances.insert(relation_instance.id(), relation_instance);
513        }
514        relation_instances
515    }
516}
517
518#[cfg(any(test, feature = "test"))]
519impl DefaultTest for RelationInstance {
520    fn default_test() -> Self {
521        RelationInstance::builder()
522            .outbound_id(Uuid::new_v4())
523            .ty(RelationInstanceTypeId::default_test())
524            .inbound_id(Uuid::new_v4())
525            .name(r_string())
526            .description(r_string())
527            .properties(PropertyInstances::default_test())
528            .extensions(Extensions::default_test())
529            .build()
530    }
531}
532
533#[cfg(any(test, feature = "test"))]
534impl DefaultTest for RelationInstances {
535    fn default_test() -> Self {
536        let relation_instances = RelationInstances::new();
537        let mut rng = rand::rng();
538        for _ in 0..rng.random_range(0..10) {
539            relation_instances.push(RelationInstance::default_test());
540        }
541        relation_instances
542    }
543}
544
545fn add_json_schema_id_property(schema: &mut Schema) {
546    crate::json_schema::add_json_schema_id_property(schema, JSON_SCHEMA_ID_RELATION_INSTANCE);
547}
548
549#[cfg(test)]
550mod tests {
551    use schemars::schema_for;
552    use serde_json::json;
553    use uuid::Uuid;
554
555    use crate::ComponentTypeId;
556    use crate::ComponentTypeIdContainer;
557    use crate::ComponentTypeIds;
558    use crate::Extension;
559    use crate::ExtensionContainer;
560    use crate::ExtensionTypeId;
561    use crate::Extensions;
562    use crate::MutablePropertyInstanceSetter;
563    use crate::NamespacedTypeGetter;
564    use crate::PropertyInstanceGetter;
565    use crate::PropertyInstances;
566    use crate::RelationInstance;
567    use crate::RelationInstanceId;
568    use crate::RelationInstanceTypeId;
569    use crate::RelationTypeId;
570    use crate::TypeDefinitionGetter;
571    use crate::TypeIdType;
572    use reactive_graph_utils_test::r_string;
573
574    #[test]
575    fn relation_instance_builder_test() {
576        let namespace = r_string();
577        let type_name = r_string();
578        let ty = RelationTypeId::new_from_type(&namespace, &type_name);
579
580        let outbound_id = Uuid::new_v4();
581        let inbound_id = Uuid::new_v4();
582
583        let property_1_name = r_string();
584        let property_1_value = r_string();
585        let properties = PropertyInstances::new().property(&property_1_name, json!(property_1_value));
586
587        let instance_ty = RelationInstanceTypeId::new_with_random_instance_id(&ty);
588        let instance_id = instance_ty.instance_id();
589
590        let id = RelationInstanceId::new(outbound_id, &instance_ty, inbound_id);
591
592        let relation_instance = RelationInstance::builder()
593            .outbound_id(outbound_id)
594            .ty(instance_ty)
595            .name(r_string())
596            .description(r_string())
597            .inbound_id(inbound_id)
598            .properties(properties)
599            .build();
600
601        assert_eq!(namespace, relation_instance.namespace());
602        assert_eq!(format!("{}__{}", type_name, instance_id), relation_instance.type_name());
603        assert_eq!(ty, relation_instance.relation_type_id());
604        assert_eq!(id, relation_instance.id());
605        assert_eq!(property_1_value.clone().as_str(), relation_instance.get(property_1_name.clone()).unwrap().as_str().unwrap());
606    }
607
608    #[test]
609    fn relation_instance_test() {
610        let namespace = r_string();
611        let outbound_id = Uuid::new_v4();
612        let inbound_id = Uuid::new_v4();
613        let type_name = r_string();
614        let name = r_string();
615        let description = r_string();
616        let property_name = r_string();
617        let property_value = json!(r_string());
618        let properties = PropertyInstances::new().property(&property_name, property_value.clone());
619
620        let component_namespace = r_string();
621        let component_name = r_string();
622        let component_ty = ComponentTypeId::new_from_type(&component_namespace, &component_name);
623        let components = ComponentTypeIds::new().component(component_ty.clone());
624
625        let extension_namespace = r_string();
626        let extension_name = r_string();
627        let extension_ty = ExtensionTypeId::new_from_type(&extension_namespace, &extension_name);
628        let extension_value = json!("extension_value");
629        let extension = Extension {
630            ty: extension_ty.clone(),
631            description: r_string(),
632            extension: extension_value.clone(),
633        };
634        let other_extension_ty = ExtensionTypeId::new_from_type(&extension_namespace, &r_string());
635        let other_extension = Extension::new(&other_extension_ty, r_string(), extension_value.clone());
636        let extensions = Extensions::new().extension(extension.clone()).extension(other_extension.clone());
637
638        let ty = RelationInstanceTypeId::new_from_type_unique_id(&namespace, &type_name);
639        let relation_instance = RelationInstance {
640            outbound_id,
641            ty: ty.clone(),
642            inbound_id,
643            name: name.to_string(),
644            description: description.to_string(),
645            properties: properties.clone(),
646            components: components.clone(),
647            extensions: extensions.clone(),
648        };
649        assert_eq!(namespace, relation_instance.namespace());
650        assert_eq!(outbound_id, relation_instance.outbound_id);
651        assert_eq!(type_name.clone(), relation_instance.type_name());
652        assert_eq!(inbound_id, relation_instance.inbound_id);
653        assert_eq!(name, relation_instance.name);
654        assert_eq!(description, relation_instance.description);
655        assert_eq!(properties.clone(), relation_instance.properties.clone());
656        assert!(relation_instance.get(property_name.clone()).is_some());
657        assert!(relation_instance.get(r_string()).is_none());
658        assert_eq!(property_value.clone(), relation_instance.get(property_name.clone()).unwrap());
659        assert!(relation_instance.components.contains(&component_ty.clone()));
660        assert!(relation_instance.components.is_a(&component_ty));
661        assert!(relation_instance.is_a(&component_ty));
662        assert!(!relation_instance.is_a(&ComponentTypeId::generate_random()));
663        assert!(relation_instance.extensions.has_own_extension(&extension_ty));
664        assert!(relation_instance.has_own_extension(&extension_ty));
665        let non_existing_extension = ExtensionTypeId::new_from_type(r_string(), r_string());
666        assert!(!relation_instance.has_own_extension(&non_existing_extension));
667        assert_eq!(extension.extension, relation_instance.get_own_extension(&extension_ty).unwrap().extension);
668
669        assert_eq!(
670            format!("{}-[{}]->{}", relation_instance.outbound_id, relation_instance.ty, relation_instance.inbound_id),
671            format!("{}", relation_instance)
672        );
673    }
674
675    #[test]
676    fn relation_instance_id_from_type_unique_id_test() {
677        let namespace = r_string();
678        let type_name = r_string();
679        let outbound_id = Uuid::new_v4();
680        let inbound_id = Uuid::new_v4();
681        let ty = RelationInstanceTypeId::new_from_type_unique_id(&namespace, &type_name);
682        assert_eq!(namespace, ty.namespace());
683        assert_eq!(type_name, ty.type_name());
684        assert_eq!(format!("r__{}__{}", namespace, type_name), ty.type_definition().to_string());
685        let relation_instance = RelationInstance {
686            outbound_id,
687            ty: ty.clone(),
688            inbound_id,
689            name: r_string(),
690            description: r_string(),
691            properties: PropertyInstances::new(),
692            components: ComponentTypeIds::new(),
693            extensions: Extensions::new(),
694        };
695
696        let rity = relation_instance.id();
697        assert_eq!(namespace, rity.namespace());
698        assert_eq!(type_name, rity.type_name());
699        assert_eq!(format!("{outbound_id}-[r__{namespace}__{type_name}]->{inbound_id}"), format!("{rity}"));
700
701        let rty = relation_instance.relation_type_id();
702        assert_eq!(namespace, rty.namespace());
703        assert_eq!(type_name, rty.type_name());
704        assert_eq!(format!("r__{namespace}__{type_name}"), format!("{rty}"));
705    }
706
707    #[test]
708    fn relation_instance_id_from_type_unique_for_instance_id_test() {
709        let namespace = r_string();
710        let type_name = r_string();
711        let instance_id = r_string();
712        let outbound_id = Uuid::new_v4();
713        let inbound_id = Uuid::new_v4();
714        let ty = RelationInstanceTypeId::new_from_type_unique_for_instance_id(&namespace, &type_name, &instance_id);
715        assert_eq!(namespace, ty.namespace());
716        assert_eq!(type_name, ty.relation_type_id().type_name());
717        assert_eq!(format!("{type_name}__{instance_id}"), ty.type_name());
718        assert_eq!(format!("r__{namespace}__{type_name}__{instance_id}"), ty.type_definition().to_string());
719        let relation_instance = RelationInstance {
720            outbound_id,
721            ty: ty.clone(),
722            inbound_id,
723            name: r_string(),
724            description: r_string(),
725            properties: PropertyInstances::new(),
726            components: ComponentTypeIds::new(),
727            extensions: Extensions::new(),
728        };
729
730        let rity = relation_instance.id();
731        assert_eq!(namespace, rity.namespace());
732        assert_eq!(format!("{type_name}__{instance_id}"), rity.type_name());
733        assert_eq!(format!("{outbound_id}-[r__{namespace}__{type_name}__{instance_id}]->{inbound_id}"), format!("{rity}"));
734
735        let rty = relation_instance.relation_type_id();
736        assert_eq!(namespace, rty.namespace());
737        assert_eq!(type_name, rty.type_name());
738        assert_eq!(format!("r__{namespace}__{type_name}"), format!("{rty}"));
739
740        assert_eq!(format!("r__{namespace}__{type_name}__{instance_id}"), format!("{}", relation_instance.ty));
741    }
742
743    #[test]
744    fn create_relation_instance_test() {
745        let namespace = r_string();
746        let outbound_id = Uuid::new_v4();
747        let inbound_id = Uuid::new_v4();
748        let type_name = r_string();
749        let property_name = r_string();
750        let property_value = json!(r_string());
751        let properties = PropertyInstances::new().property(&property_name, property_value.clone());
752        let ty = RelationInstanceTypeId::new_from_type_unique_id(&namespace, &type_name);
753        let relation_instance = RelationInstance::new(outbound_id, ty, inbound_id, properties.clone());
754        assert_eq!(namespace, relation_instance.namespace());
755        assert_eq!(outbound_id, relation_instance.outbound_id);
756        assert_eq!(type_name, relation_instance.type_name());
757        assert_eq!(inbound_id, relation_instance.inbound_id);
758        assert_eq!(properties.clone(), relation_instance.properties.clone());
759        assert!(relation_instance.get(property_name.clone()).is_some());
760        assert!(relation_instance.get(r_string()).is_none());
761        assert_eq!(property_value.clone(), relation_instance.get(property_name.clone()).unwrap());
762    }
763
764    #[test]
765    fn create_relation_instance_without_properties_test() {
766        let namespace = r_string();
767        let outbound_id = Uuid::new_v4();
768        let inbound_id = Uuid::new_v4();
769        let type_name = r_string();
770        let ty = RelationInstanceTypeId::new_from_type_unique_id(&namespace, &type_name);
771        let relation_instance = RelationInstance::new_without_properties(outbound_id, ty.clone(), inbound_id);
772        assert_eq!(namespace, relation_instance.namespace());
773        assert_eq!(outbound_id, relation_instance.outbound_id);
774        assert_eq!(type_name, relation_instance.type_name());
775        assert_eq!(inbound_id, relation_instance.inbound_id);
776        assert_eq!(0, relation_instance.properties.len());
777    }
778
779    #[test]
780    fn relation_instance_typed_getter_test() {
781        let namespace = r_string();
782        let outbound_id = Uuid::new_v4();
783        let inbound_id = Uuid::new_v4();
784        let type_name = r_string();
785        let property_name = r_string();
786        let properties = PropertyInstances::new().property(&property_name, json!(false));
787        let ty = RelationInstanceTypeId::new_from_type_unique_id(&namespace, &type_name);
788        let mut i = RelationInstance::new(outbound_id, ty.clone(), inbound_id, properties.clone());
789        i.set(property_name.clone(), json!(true));
790        assert!(i.as_bool(property_name.clone()).unwrap());
791        i.set(property_name.clone(), json!(false));
792        assert!(!i.as_bool(property_name.clone()).unwrap());
793        i.set(property_name.clone(), json!(123));
794        assert_eq!(123, i.as_u64(property_name.clone()).unwrap());
795        i.set(property_name.clone(), json!(-123));
796        assert_eq!(-123, i.as_i64(property_name.clone()).unwrap());
797        i.set(property_name.clone(), json!(1.23));
798        assert_eq!(1.23, i.as_f64(property_name.clone()).unwrap());
799        let s = r_string();
800        i.set(property_name.clone(), json!(s.clone()));
801        assert_eq!(s, i.as_string(property_name.clone()).unwrap());
802        i.set(property_name.clone(), json!([]));
803        assert_eq!(0, i.as_array(property_name.clone()).unwrap().len());
804        i.set(property_name.clone(), json!({}));
805        assert_eq!(0, i.as_object(property_name.clone()).unwrap().len());
806    }
807
808    #[test]
809    fn relation_instance_get_key_test() {
810        let namespace = r_string();
811        let outbound_id = Uuid::new_v4();
812        let inbound_id = Uuid::new_v4();
813        let type_name = r_string();
814        let name = r_string();
815        let description = r_string();
816        let ty = RelationInstanceTypeId::new_from_type_unique_id(&namespace, &type_name);
817        let relation_instance = RelationInstance {
818            outbound_id,
819            ty: ty.clone(),
820            inbound_id,
821            name: name.to_string(),
822            description: description.to_string(),
823            properties: PropertyInstances::new(),
824            components: ComponentTypeIds::new(),
825            extensions: Extensions::new(),
826        };
827
828        assert_eq!(ty, relation_instance.ty);
829        assert_eq!(ty.relation_type_id(), relation_instance.relation_type_id());
830    }
831
832    #[test]
833    fn relation_instance_ser_test() {
834        let rty = RelationTypeId::new_from_type("rnr", "rtr");
835        let ty = RelationInstanceTypeId::new_unique_for_instance_id(rty.clone(), "result__lhs");
836        let outbound_id = Uuid::new_v4();
837        let inbound_id = Uuid::new_v4();
838        let relation_instance = RelationInstance::new(outbound_id, ty, inbound_id, PropertyInstances::new());
839        println!("{}", serde_json::to_string_pretty(&relation_instance).expect("Failed to serialize relation instance"));
840    }
841    #[test]
842    fn relation_instance_de_test() {
843        let s = r#"{
844  "outbound_id": "d82cc81a-e0e5-4de8-8b87-9b5bed0de795",
845  "namespace": "rnr",
846  "type_name": "rtr",
847  "instance_id": "result__lhs",
848  "inbound_id": "3f13400e-9286-441d-b85f-ef5df2177e7c",
849  "name": "BIVS93iu",
850  "description": "B0IgcIiV",
851  "components": [
852    {
853      "namespace": "mno",
854      "type_name": "pqr"
855    }
856  ],
857  "properties": {
858      "property_name": "property_value"
859  },
860  "extensions": [
861    {
862      "namespace": "ext_namespace",
863      "type_name": "ext_name",
864      "extension": "ext_value"
865    },
866    {
867      "namespace": "other_ext_namespace",
868      "type_name": "other_ext_name",
869      "extension": "other_extension_value"
870    }
871  ]
872}"#;
873        let relation_instance: RelationInstance = serde_json::from_str(s).unwrap();
874        assert_eq!("d82cc81a-e0e5-4de8-8b87-9b5bed0de795", relation_instance.outbound_id.to_string());
875        assert_eq!("3f13400e-9286-441d-b85f-ef5df2177e7c", relation_instance.inbound_id.to_string());
876        assert_eq!("rnr", relation_instance.namespace());
877        assert_eq!("rtr__result__lhs", relation_instance.type_name());
878        assert_eq!("rtr", relation_instance.relation_type_id().type_name());
879        assert_eq!("result__lhs", relation_instance.instance_id());
880        assert_eq!("r__rnr__rtr__result__lhs", relation_instance.ty.to_string());
881        assert_eq!(TypeIdType::RelationType, relation_instance.type_definition().type_id_type);
882        assert_eq!("BIVS93iu", relation_instance.name);
883        assert_eq!("B0IgcIiV", relation_instance.description);
884        assert_eq!("property_value", relation_instance.properties.get("property_name").unwrap().as_str().unwrap());
885        assert_eq!(2, relation_instance.extensions.len());
886        assert!(
887            relation_instance
888                .extensions
889                .has_own_extension(&ExtensionTypeId::new_from_type("ext_namespace", "ext_name"))
890        );
891        assert_eq!(
892            json!("ext_value"),
893            relation_instance
894                .extensions
895                .get_own_extension(&ExtensionTypeId::new_from_type("ext_namespace", "ext_name"))
896                .unwrap()
897                .extension
898        );
899        assert!(
900            relation_instance
901                .extensions
902                .has_own_extension(&ExtensionTypeId::new_from_type("other_ext_namespace", "other_ext_name"))
903        );
904        assert_eq!(
905            json!("other_extension_value"),
906            relation_instance
907                .extensions
908                .get_own_extension(&ExtensionTypeId::new_from_type("other_ext_namespace", "other_ext_name"))
909                .unwrap()
910                .extension
911        );
912    }
913
914    #[test]
915    fn relation_instance_json_schema() {
916        let schema = schema_for!(RelationInstance);
917        println!("{}", serde_json::to_string_pretty(&schema).unwrap());
918    }
919}