reactive_graph_reactive_model_impl/relations/
reactive_relation.rs

1use std::fmt::Display;
2use std::fmt::Formatter;
3use std::ops::Deref;
4use std::sync::Arc;
5
6use dashmap::DashMap;
7use serde::Serialize;
8use serde::Serializer;
9use serde_json::Map;
10use serde_json::Value;
11use typed_builder::TypedBuilder;
12
13use crate::ReactiveEntity;
14use crate::ReactiveProperties;
15use crate::ReactiveProperty;
16use reactive_graph_behaviour_model_api::BehaviourTypeId;
17use reactive_graph_behaviour_model_api::BehaviourTypeIds;
18use reactive_graph_behaviour_model_api::BehaviourTypesContainer;
19use reactive_graph_graph::Component;
20use reactive_graph_graph::ComponentContainer;
21use reactive_graph_graph::ComponentTypeId;
22use reactive_graph_graph::ComponentTypeIds;
23use reactive_graph_graph::Extensions;
24use reactive_graph_graph::JsonSchemaId;
25use reactive_graph_graph::Mutability;
26use reactive_graph_graph::NamespacedTypeGetter;
27use reactive_graph_graph::PropertyInstanceGetter;
28use reactive_graph_graph::PropertyInstanceSetter;
29use reactive_graph_graph::PropertyInstances;
30use reactive_graph_graph::PropertyType;
31use reactive_graph_graph::PropertyTypes;
32use reactive_graph_graph::RelationInstance;
33use reactive_graph_graph::RelationInstanceId;
34use reactive_graph_graph::RelationInstanceTypeId;
35use reactive_graph_graph::RelationType;
36use reactive_graph_graph::RelationTypeId;
37use reactive_graph_graph::TypeDefinition;
38use reactive_graph_graph::TypeDefinitionGetter;
39use reactive_graph_graph::instances::named::NamedInstanceContainer;
40use reactive_graph_reactive_model_api::ReactiveInstance;
41use reactive_graph_reactive_model_api::ReactivePropertyContainer;
42
43/// Reactive instance of a relation in the directed property graph.
44///
45/// Property Graph: The relation instance can store properties.
46///
47/// Directed Graph: The direction of the relation point from the outbound
48/// entity instance to the inbound entity instance.
49///
50/// Reactive Instance: The properties are streams with a local copies of
51/// the last result. The streams can be connected, combined, folded or zipped.
52///
53/// One example for a directed reactive relation instance is a connector which
54/// propagates changes on a property of the outbound entity to a property of
55/// the inbound entity.
56///
57/// Another example would be the velocity transformation which are also using
58/// the streams of the properties of the outbound entity, the inbound entity
59/// and/or the relation itself.
60///
61/// Last but not least relation instances can be used for semantic
62/// representations like the current camera of a player:
63/// Player--(CurrentCamera)-->Camera
64///
65#[derive(TypedBuilder)]
66#[builder(
67    build_method(vis="pub", into=ReactiveRelation),
68    builder_method(vis = ""),
69    builder_type(vis="pub", name=ReactiveRelationInstanceBuilder),
70)]
71pub struct ReactiveRelationInstance {
72    // Possible optimization: Final field id would speed up getting the id
73    // pub id: RelationInstanceId,
74    /// The outbound entity instance.
75    pub outbound: ReactiveEntity,
76
77    /// The type definition of the relation type.
78    #[builder(setter(into))]
79    pub ty: RelationInstanceTypeId,
80
81    /// The outbound entity instance.
82    pub inbound: ReactiveEntity,
83
84    /// The name of the relation instance.
85    #[builder(default, setter(into))]
86    pub name: String,
87
88    /// Textual description of the relation instance.
89    #[builder(default, setter(into))]
90    pub description: String,
91
92    /// The reactive properties.
93    #[builder(default, setter(into))]
94    pub properties: ReactiveProperties<RelationInstanceId>,
95
96    /// The names of the components which are applied on this relation instance.
97    #[builder(default, setter(into))]
98    pub components: ComponentTypeIds,
99
100    /// The names of the behaviours which are applied on this relation instance.
101    #[builder(default, setter(into))]
102    pub behaviours: BehaviourTypeIds,
103}
104
105#[allow(clippy::result_unit_err)]
106impl ReactiveRelationInstance {
107    pub fn new_from_properties<T: Into<RelationInstanceTypeId>, P: Into<PropertyInstances>>(
108        outbound: ReactiveEntity,
109        ty: T,
110        inbound: ReactiveEntity,
111        properties: P,
112    ) -> ReactiveRelationInstance {
113        let ty = ty.into();
114        let id = RelationInstanceId::new(outbound.id, ty.clone(), inbound.id);
115        let properties = ReactiveProperties::new_with_id_from_properties(id.clone(), properties.into());
116        ReactiveRelationInstance {
117            outbound,
118            ty,
119            inbound,
120            name: String::new(),
121            description: String::new(),
122            properties,
123            components: ComponentTypeIds::new(),
124            behaviours: BehaviourTypeIds::new(),
125        }
126    }
127
128    pub fn new_from_instance(outbound: ReactiveEntity, inbound: ReactiveEntity, instance: RelationInstance) -> ReactiveRelationInstance {
129        let id = instance.id();
130        let properties = ReactiveProperties::new_with_id_from_properties(id.clone(), instance.properties);
131        // let properties = instance.properties;
132        // ::<RelationInstanceId>
133        // let properties = instance
134        //     .properties
135        //     .iter()
136        //     // TODO: mutability
137        //     .map(|(name, value)| (name.clone(), ReactiveProperty::new(instance.ty.clone(), name.clone(), Mutable, value.clone())))
138        //     .collect();
139        ReactiveRelationInstance {
140            outbound,
141            ty: instance.ty,
142            inbound,
143            name: instance.name,
144            description: instance.description,
145            properties,
146            components: ComponentTypeIds::new(),
147            behaviours: BehaviourTypeIds::new(),
148        }
149    }
150
151    // // TODO: remove?
152    // pub fn new_from_type_with_properties<S: Into<String>, P: Into<PropertyInstances>>(
153    //     namespace: S,
154    //     outbound: ReactiveEntity,
155    //     type_name: S,
156    //     inbound: ReactiveEntity,
157    //     properties: P,
158    // ) -> ReactiveRelationInstance {
159    //     let ty = RelationTypeId::new_from_type(namespace.into(), type_name.into());
160    //     let id = RelationInstanceId::new(outbound.id, ty.clone(), inbound.id);
161    //     let properties = properties.into();
162    //     let properties = ReactiveProperties::new_with_id_from_properties(id.clone(), instance.properties);
163    //     let ty = RelationInstanceTypeId::new_from_type_unique_id(namespace, type_name);
164    //     let properties = properties
165    //         .iter()
166    //         .map(|(name, value)| {
167    //             (
168    //                 name.clone(),
169    //                 ReactiveProperty::new(
170    //                     ty.clone(),
171    //                     name.clone(),
172    //                     // TODO: mutability
173    //                     Mutable,
174    //                     value.clone(),
175    //                 ),
176    //             )
177    //         })
178    //         .collect();
179    //     ReactiveRelationInstance {
180    //         outbound,
181    //         ty,
182    //         inbound,
183    //         description: String::new(),
184    //         properties,
185    //         components: ComponentTypeIds::new(),
186    //         behaviours: BehaviourTypeIds::new(),
187    //     }
188    // }
189
190    /// Returns the inner relation type id.
191    pub fn relation_type_id(&self) -> RelationTypeId {
192        self.ty.relation_type_id()
193    }
194
195    /// Returns the relation instance type id.
196    pub fn instance_id(&self) -> String {
197        self.ty.instance_id()
198    }
199}
200
201#[derive(Clone)]
202pub struct ReactiveRelation(Arc<ReactiveRelationInstance>);
203
204impl ReactiveRelation {
205    pub fn builder() -> ReactiveRelationInstanceBuilder {
206        ReactiveRelationInstance::builder()
207    }
208
209    #[allow(clippy::type_complexity)]
210    pub fn builder_with_entities(
211        outbound: ReactiveEntity,
212        ty: &RelationInstanceTypeId,
213        inbound: ReactiveEntity,
214    ) -> ReactiveRelationInstanceBuilder<((ReactiveEntity,), (RelationInstanceTypeId,), (ReactiveEntity,), (), (), (), (), ())> {
215        ReactiveRelation::builder().outbound(outbound).ty(ty).inbound(inbound)
216    }
217
218    /// Creates a builder for the given relation instance type id.
219    /// Generates an id for the reactive relation.
220    /// Converts property types into reactive properties and initializes the properties with default values.
221    #[allow(clippy::type_complexity)]
222    pub fn builder_with_entities_and_properties(
223        outbound: ReactiveEntity,
224        ty: &RelationInstanceTypeId,
225        inbound: ReactiveEntity,
226        properties: &PropertyTypes,
227    ) -> ReactiveRelationInstanceBuilder<(
228        (ReactiveEntity,),
229        (RelationInstanceTypeId,),
230        (ReactiveEntity,),
231        (),
232        (),
233        (ReactiveProperties<RelationInstanceId>,),
234        (),
235        (),
236    )> {
237        let id = RelationInstanceId::new(outbound.id, ty, inbound.id);
238        let properties = PropertyInstances::new_from_property_types_with_defaults(properties);
239        let reactive_properties: ReactiveProperties<RelationInstanceId> = ReactiveProperties::new_with_id_from_properties(id, properties);
240        ReactiveRelation::builder_with_entities(outbound, ty, inbound).properties(reactive_properties)
241    }
242
243    #[allow(clippy::type_complexity)]
244    pub fn builder_from_type_with_unique_id(
245        outbound: ReactiveEntity,
246        relation_type: &RelationType,
247        inbound: ReactiveEntity,
248    ) -> ReactiveRelationInstanceBuilder<(
249        (ReactiveEntity,),
250        (RelationInstanceTypeId,),
251        (ReactiveEntity,),
252        (),
253        (),
254        (ReactiveProperties<RelationInstanceId>,),
255        (),
256        (),
257    )> {
258        let ty = RelationInstanceTypeId::new_unique_id(&relation_type.ty);
259        ReactiveRelation::builder_with_entities_and_properties(outbound, &ty, inbound, &relation_type.properties)
260    }
261
262    #[allow(clippy::type_complexity)]
263    pub fn builder_from_type_with_unique_instance_id(
264        outbound: ReactiveEntity,
265        relation_type: &RelationType,
266        instance_id: String,
267        inbound: ReactiveEntity,
268    ) -> ReactiveRelationInstanceBuilder<(
269        (ReactiveEntity,),
270        (RelationInstanceTypeId,),
271        (ReactiveEntity,),
272        (),
273        (),
274        (ReactiveProperties<RelationInstanceId>,),
275        (),
276        (),
277    )> {
278        let ty = RelationInstanceTypeId::new_unique_for_instance_id(&relation_type.ty, instance_id);
279        ReactiveRelation::builder_with_entities_and_properties(outbound, &ty, inbound, &relation_type.properties)
280    }
281
282    #[allow(clippy::type_complexity)]
283    pub fn builder_from_type_with_random_instance_id(
284        outbound: ReactiveEntity,
285        relation_type: &RelationType,
286        inbound: ReactiveEntity,
287    ) -> ReactiveRelationInstanceBuilder<(
288        (ReactiveEntity,),
289        (RelationInstanceTypeId,),
290        (ReactiveEntity,),
291        (),
292        (),
293        (ReactiveProperties<RelationInstanceId>,),
294        (),
295        (),
296    )> {
297        let ty = RelationInstanceTypeId::new_with_random_instance_id(&relation_type.ty);
298        ReactiveRelation::builder_with_entities_and_properties(outbound, &ty, inbound, &relation_type.properties)
299    }
300    // }
301    //
302    // impl ReactiveRelation {
303    pub fn new_from_properties(
304        outbound: ReactiveEntity,
305        ty: RelationInstanceTypeId,
306        inbound: ReactiveEntity,
307        properties: DashMap<String, Value>,
308    ) -> ReactiveRelation {
309        ReactiveRelationInstance::new_from_properties(outbound, ty, inbound, properties).into()
310    }
311
312    pub fn new_from_instance(outbound: ReactiveEntity, inbound: ReactiveEntity, instance: RelationInstance) -> ReactiveRelation {
313        ReactiveRelationInstance::new_from_instance(outbound, inbound, instance).into()
314    }
315
316    // pub fn new_from_type_with_properties<S: Into<String>>(
317    //     namespace: S,
318    //     outbound: ReactiveEntity,
319    //     type_name: S,
320    //     inbound: ReactiveEntity,
321    //     properties: HashMap<String, Value>,
322    // ) -> ReactiveRelation {
323    //     ReactiveRelationInstance::new_from_type_with_properties(namespace, outbound, type_name, inbound, properties).into()
324    // }
325}
326
327impl NamedInstanceContainer for ReactiveRelation {
328    fn name(&self) -> String {
329        self.name.clone()
330    }
331
332    fn description(&self) -> String {
333        self.description.clone()
334    }
335}
336
337impl Deref for ReactiveRelation {
338    type Target = Arc<ReactiveRelationInstance>;
339
340    fn deref(&self) -> &Self::Target {
341        &self.0
342    }
343}
344
345impl ReactiveInstance<RelationInstanceId> for ReactiveRelation {
346    /// Returns the relation instance id.
347    fn id(&self) -> RelationInstanceId {
348        RelationInstanceId::new(self.outbound.id, self.ty.clone(), self.inbound.id)
349    }
350}
351
352impl ReactivePropertyContainer for ReactiveRelation {
353    fn tick_checked(&self) {
354        for property_instance in self.properties.iter() {
355            property_instance.tick_checked();
356        }
357    }
358
359    fn tick(&self) {
360        for property_instance in self.properties.iter() {
361            property_instance.tick();
362        }
363    }
364
365    fn has_property(&self, name: &str) -> bool {
366        self.properties.contains_key(name)
367    }
368
369    fn add_property<S: Into<String>>(&self, name: S, mutability: Mutability, value: Value) {
370        let name = name.into();
371        let id = self.id();
372        if !self.properties.contains_key(name.as_str()) {
373            let property_instance = ReactiveProperty::new(id.clone(), name.clone(), mutability, value);
374            self.properties.insert(name, property_instance);
375        }
376    }
377
378    fn add_property_by_type(&self, property: &PropertyType) {
379        let property_instance = ReactiveProperty::new(self.id().clone(), &property.name, property.mutability, property.data_type.default_value());
380        self.properties.insert(property.name.clone(), property_instance);
381    }
382
383    fn remove_property<S: Into<String>>(&self, name: S) {
384        let name = name.into();
385        self.properties.retain(|property_name, _| property_name != &name);
386    }
387
388    fn observe_with_handle<F>(&self, name: &str, subscriber: F, handle_id: u128)
389    where
390        F: FnMut(&Value) + 'static + Send,
391    {
392        if let Some(property) = self.properties.get(name) {
393            property.stream.read().unwrap().observe_with_handle(subscriber, handle_id);
394        }
395    }
396
397    fn remove_observer(&self, name: &str, handle_id: u128) {
398        if let Some(property) = self.properties.get(name) {
399            property.stream.read().unwrap().remove(handle_id);
400        }
401    }
402
403    fn remove_observers(&self, name: &str) {
404        if let Some(property_instance) = self.properties.get(name) {
405            property_instance.stream.read().unwrap().clear();
406        }
407    }
408
409    fn remove_all_observers(&self) {
410        for property_instance in self.properties.iter() {
411            property_instance.stream.read().unwrap().clear();
412        }
413    }
414}
415
416impl ComponentContainer for ReactiveRelation {
417    fn get_components(&self) -> ComponentTypeIds {
418        self.components.clone()
419        // self.components.iter().map(|c| c.key().clone()).collect()
420    }
421
422    fn add_component(&self, ty: ComponentTypeId) {
423        self.components.insert(ty);
424    }
425
426    fn add_component_with_properties(&self, component: &Component) {
427        self.add_component(component.ty.clone());
428        for property_type in component.properties.iter() {
429            if !self.properties.contains_key(&property_type.name) {
430                self.add_property_by_type(&property_type);
431            }
432        }
433    }
434
435    fn remove_component(&self, ty: &ComponentTypeId) {
436        self.components.remove(ty);
437    }
438
439    fn is_a(&self, ty: &ComponentTypeId) -> bool {
440        self.components.contains(ty)
441    }
442}
443
444impl BehaviourTypesContainer for ReactiveRelation {
445    fn get_behaviours(&self) -> Vec<BehaviourTypeId> {
446        self.behaviours.iter().map(|b| b.key().clone()).collect()
447    }
448
449    fn add_behaviour(&self, ty: BehaviourTypeId) {
450        self.behaviours.insert(ty);
451    }
452
453    fn remove_behaviour(&self, ty: &BehaviourTypeId) {
454        self.behaviours.remove(ty);
455    }
456
457    fn behaves_as(&self, ty: &BehaviourTypeId) -> bool {
458        self.behaviours.contains(ty)
459    }
460}
461
462impl PropertyInstanceGetter for ReactiveRelation {
463    fn get<S: Into<String>>(&self, property_name: S) -> Option<Value> {
464        self.properties.get(&property_name.into()).map(|p| p.get())
465    }
466
467    fn as_bool<S: Into<String>>(&self, property_name: S) -> Option<bool> {
468        self.properties.get(&property_name.into()).and_then(|p| p.as_bool())
469    }
470
471    fn as_u64<S: Into<String>>(&self, property_name: S) -> Option<u64> {
472        self.properties.get(&property_name.into()).and_then(|p| p.as_u64())
473    }
474
475    fn as_i64<S: Into<String>>(&self, property_name: S) -> Option<i64> {
476        self.properties.get(&property_name.into()).and_then(|p| p.as_i64())
477    }
478
479    fn as_f64<S: Into<String>>(&self, property_name: S) -> Option<f64> {
480        self.properties.get(&property_name.into()).and_then(|p| p.as_f64())
481    }
482
483    fn as_string<S: Into<String>>(&self, property_name: S) -> Option<String> {
484        self.properties.get(&property_name.into()).and_then(|p| p.as_string())
485    }
486
487    fn as_array<S: Into<String>>(&self, property_name: S) -> Option<Vec<Value>> {
488        self.properties.get(&property_name.into()).and_then(|p| p.as_array())
489    }
490
491    fn as_object<S: Into<String>>(&self, property_name: S) -> Option<Map<String, Value>> {
492        self.properties.get(&property_name.into()).and_then(|p| p.as_object())
493    }
494}
495
496impl PropertyInstanceSetter for ReactiveRelation {
497    fn set_checked<S: Into<String>>(&self, property_name: S, value: Value) {
498        if let Some(instance) = self.properties.get(&property_name.into()) {
499            instance.set_checked(value);
500        }
501    }
502
503    fn set<S: Into<String>>(&self, property_name: S, value: Value) {
504        if let Some(instance) = self.properties.get(&property_name.into()) {
505            instance.set(value);
506        }
507    }
508
509    fn set_no_propagate_checked<S: Into<String>>(&self, property_name: S, value: Value) {
510        if let Some(instance) = self.properties.get(&property_name.into()) {
511            instance.set_no_propagate_checked(value);
512        }
513    }
514
515    fn set_no_propagate<S: Into<String>>(&self, property_name: S, value: Value) {
516        if let Some(instance) = self.properties.get(&property_name.into()) {
517            instance.set_no_propagate(value);
518        }
519    }
520
521    fn mutability<S: Into<String>>(&self, property_name: S) -> Option<Mutability> {
522        self.properties.get(&property_name.into()).map(|p| p.value().mutability)
523    }
524
525    fn set_mutability<S: Into<String>>(&self, property_name: S, mutability: Mutability) {
526        if let Some(mut property_instance) = self.properties.get_mut(&property_name.into()) {
527            property_instance.set_mutability(mutability);
528        }
529    }
530}
531
532impl NamespacedTypeGetter for ReactiveRelation {
533    fn namespace(&self) -> String {
534        self.ty.namespace()
535    }
536
537    fn type_name(&self) -> String {
538        self.ty.type_name()
539    }
540}
541
542impl TypeDefinitionGetter for ReactiveRelation {
543    fn type_definition(&self) -> TypeDefinition {
544        self.ty.type_definition()
545    }
546}
547
548impl TypeDefinitionGetter for &ReactiveRelation {
549    fn type_definition(&self) -> TypeDefinition {
550        self.ty.type_definition()
551    }
552}
553
554impl Display for ReactiveRelation {
555    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
556        write!(f, "{}--[{}]-->{}", self.outbound.id, &self.ty, self.inbound.id)
557    }
558}
559
560impl From<ReactiveRelation> for RelationInstance {
561    fn from(relation: ReactiveRelation) -> Self {
562        RelationInstance {
563            outbound_id: relation.outbound.id,
564            ty: relation.ty.clone(),
565            inbound_id: relation.inbound.id,
566            name: relation.name.clone(),
567            description: relation.description.clone(),
568            properties: PropertyInstances::from(&relation.properties),
569            components: relation.components.clone(),
570            extensions: Extensions::new(),
571        }
572    }
573}
574
575impl From<&ReactiveRelation> for RelationInstance {
576    fn from(relation: &ReactiveRelation) -> Self {
577        RelationInstance {
578            outbound_id: relation.outbound.id,
579            ty: relation.ty.clone(),
580            inbound_id: relation.inbound.id,
581            name: relation.name.clone(),
582            description: relation.description.clone(),
583            properties: PropertyInstances::from(&relation.properties),
584            components: relation.components.clone(),
585            extensions: Extensions::new(),
586        }
587    }
588}
589
590impl From<ReactiveRelationInstance> for ReactiveRelation {
591    fn from(relation_instance: ReactiveRelationInstance) -> Self {
592        ReactiveRelation(Arc::new(relation_instance))
593    }
594}
595
596impl Serialize for ReactiveRelation {
597    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
598    where
599        S: Serializer,
600    {
601        let property_instances = PropertyInstances::from(&self.properties);
602        property_instances.insert("$id".to_string(), JsonSchemaId::from(&self).into());
603        property_instances.insert("outbound_id".to_string(), Value::String(self.outbound.id.to_string()));
604        property_instances.insert("instance_id".to_string(), Value::String(self.instance_id()));
605        property_instances.insert("inbound_id".to_string(), Value::String(self.inbound.id.to_string()));
606        serializer.collect_map(property_instances)
607    }
608}