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#[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 pub outbound: ReactiveEntity,
76
77 #[builder(setter(into))]
79 pub ty: RelationInstanceTypeId,
80
81 pub inbound: ReactiveEntity,
83
84 #[builder(default, setter(into))]
86 pub name: String,
87
88 #[builder(default, setter(into))]
90 pub description: String,
91
92 #[builder(default, setter(into))]
94 pub properties: ReactiveProperties<RelationInstanceId>,
95
96 #[builder(default, setter(into))]
98 pub components: ComponentTypeIds,
99
100 #[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 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 pub fn relation_type_id(&self) -> RelationTypeId {
192 self.ty.relation_type_id()
193 }
194
195 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 #[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 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 }
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 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 }
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}