reactive_graph_dynamic_graph_impl/object/flow/mutation/
update.rs

1use crate::field::to_input_type_ref;
2use crate::object::types::DynamicGraphTypeDefinition;
3use async_graphql::dynamic::Field;
4use async_graphql::dynamic::FieldFuture;
5use async_graphql::dynamic::FieldValue;
6use async_graphql::dynamic::InputValue;
7use async_graphql::dynamic::TypeRef;
8use reactive_graph_dynamic_graph_api::ImmutablePropertyError;
9use reactive_graph_dynamic_graph_api::PropertyDataTypeError;
10use reactive_graph_dynamic_graph_api::SchemaBuilderContext;
11use reactive_graph_graph::DataType;
12use reactive_graph_graph::FlowType;
13use reactive_graph_graph::Mutability::Immutable;
14use reactive_graph_graph::Mutability::Mutable;
15use reactive_graph_graph::PropertyInstanceSetter;
16use reactive_graph_reactive_model_impl::ReactiveFlow;
17use serde_json::Value;
18use serde_json::json;
19
20pub fn get_flow_update_field(flow_type: &FlowType, context: &SchemaBuilderContext) -> Option<Field> {
21    let entity_ty = flow_type.wrapper_type();
22    let entity_type = context.entity_type_manager.get(&entity_ty)?;
23    let entity_type_inner = entity_type.clone();
24    let dy_ty = DynamicGraphTypeDefinition::from(&flow_type.ty);
25    let mut update_field = Field::new("update", TypeRef::named_nn_list_nn(dy_ty.to_string()), move |ctx| {
26        let entity_type = entity_type_inner.clone();
27        FieldFuture::new(async move {
28            let flow_instances = ctx.parent_value.try_downcast_ref::<Vec<ReactiveFlow>>()?;
29            for flow_instance in flow_instances {
30                // First validate all input fields for mutability and correct datatype
31                for property in entity_type.properties.iter() {
32                    if let Ok(value) = ctx.args.try_get(&property.name) {
33                        // Fail on every property which is immutable
34                        if property.mutability == Immutable {
35                            return Err(ImmutablePropertyError(property.key().clone()).into());
36                        }
37                        match &property.data_type {
38                            DataType::Null => {
39                                return Err(PropertyDataTypeError::NullIsNotAValidDataType(property.key().clone()).into());
40                            }
41                            DataType::Bool => {
42                                if value.boolean().is_err() {
43                                    return Err(PropertyDataTypeError::ValueIsNotOfTheExpectedDataType(
44                                        property.name.clone(),
45                                        property.data_type,
46                                        DataType::Bool,
47                                    )
48                                    .into());
49                                }
50                            }
51                            DataType::Number => {
52                                if value.f64().is_err() && value.i64().is_err() && value.u64().is_err() {
53                                    return Err(PropertyDataTypeError::ValueIsNotOfTheExpectedDataType(
54                                        property.name.clone(),
55                                        property.data_type,
56                                        DataType::Number,
57                                    )
58                                    .into());
59                                }
60                            }
61                            DataType::String => {
62                                if value.string().is_err() {
63                                    return Err(PropertyDataTypeError::ValueIsNotOfTheExpectedDataType(
64                                        property.name.clone(),
65                                        property.data_type,
66                                        DataType::String,
67                                    )
68                                    .into());
69                                }
70                            }
71                            DataType::Array => {
72                                if value.list().is_err() {
73                                    return Err(PropertyDataTypeError::ValueIsNotOfTheExpectedDataType(
74                                        property.name.clone(),
75                                        property.data_type,
76                                        DataType::Array,
77                                    )
78                                    .into());
79                                }
80                            }
81                            DataType::Object => {
82                                if value.object().is_err() {
83                                    return Err(PropertyDataTypeError::ValueIsNotOfTheExpectedDataType(
84                                        property.name.clone(),
85                                        property.data_type,
86                                        DataType::Object,
87                                    )
88                                    .into());
89                                }
90                            }
91                            DataType::Any => {
92                                // Accept input of any datatype
93                            }
94                        }
95                    }
96                }
97                // Set properties
98                for property in entity_type.properties.iter() {
99                    if let Ok(value) = ctx.args.try_get(&property.name) {
100                        match &property.data_type {
101                            DataType::Null => {
102                                return Err(PropertyDataTypeError::NullIsNotAValidDataType(property.key().clone()).into());
103                            }
104                            DataType::Bool => {
105                                flow_instance.set_checked(&property.name, Value::Bool(value.boolean()?));
106                            }
107                            DataType::Number => {
108                                if let Ok(value) = value.i64() {
109                                    flow_instance.set_checked(&property.name, json!(value));
110                                } else if let Ok(value) = value.u64() {
111                                    flow_instance.set_checked(&property.name, json!(value));
112                                } else if let Ok(value) = value.f64() {
113                                    flow_instance.set_checked(&property.name, json!(value));
114                                } else {
115                                    return Err(PropertyDataTypeError::ValueIsNotOfTheExpectedDataType(
116                                        property.name.clone(),
117                                        property.data_type,
118                                        DataType::Number,
119                                    )
120                                    .into());
121                                }
122                            }
123                            DataType::String => {
124                                flow_instance.set_checked(&property.name, Value::String(value.string()?.to_string()));
125                            }
126                            DataType::Array => {
127                                let _list = value.list()?;
128                                let value = value.deserialize::<Value>()?;
129                                if !value.is_array() {
130                                    return Err(PropertyDataTypeError::ValueIsNotOfTheExpectedDataType(
131                                        property.name.clone(),
132                                        property.data_type,
133                                        DataType::Array,
134                                    )
135                                    .into());
136                                }
137                                flow_instance.set_checked(&property.name, value);
138                            }
139                            DataType::Object => {
140                                let value = value.deserialize::<Value>()?;
141                                if !value.is_object() {
142                                    return Err(PropertyDataTypeError::ValueIsNotOfTheExpectedDataType(
143                                        property.name.clone(),
144                                        property.data_type,
145                                        DataType::Object,
146                                    )
147                                    .into());
148                                }
149                                flow_instance.set_checked(&property.name, value);
150                            }
151                            DataType::Any => {
152                                // If it's possible to deserialize, accept the input
153                                let value = value.deserialize::<Value>()?;
154                                flow_instance.set_checked(&property.name, value);
155                            }
156                        }
157                    }
158                }
159            }
160            Ok(Some(FieldValue::list(
161                flow_instances.iter().map(|flow_instance| FieldValue::owned_any(flow_instance.clone())),
162            )))
163        })
164    });
165    let mut has_updatable_property = false;
166    for property in entity_type.properties.iter() {
167        if property.mutability == Mutable {
168            if let Some(type_ref) = to_input_type_ref(property.value(), true) {
169                update_field = update_field.argument(InputValue::new(&property.name, type_ref));
170                has_updatable_property = true;
171            }
172        }
173    }
174    if !has_updatable_property {
175        return None;
176    }
177    Some(update_field)
178}