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