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#[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 pub outbound_id: Uuid,
79
80 #[serde(flatten)]
82 #[builder(setter(into))]
83 pub ty: RelationInstanceTypeId,
84
85 pub inbound_id: Uuid,
87
88 #[serde(default = "String::new")]
90 #[builder(default, setter(into))]
91 pub name: String,
92
93 #[serde(default = "String::new")]
95 #[builder(default, setter(into))]
96 pub description: String,
97
98 #[serde(default = "PropertyInstances::new")]
105 #[builder(default, setter(into))]
106 pub properties: PropertyInstances,
107
108 #[serde(default = "ComponentTypeIds::new")]
110 #[builder(default, setter(into))]
111 pub components: ComponentTypeIds,
112
113 #[serde(default = "Extensions::new")]
115 #[builder(default, setter(into))]
116 pub extensions: Extensions,
117}
118
119impl RelationInstance {
120 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 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 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 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 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 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 pub fn relation_type_id(&self) -> RelationTypeId {
220 self.ty.relation_type_id()
221 }
222
223 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 }
368}
369
370#[derive(Clone, Debug, Default)]
371pub 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 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}