hit_data/hit_mod/
hit.rs

1use linked_hash_map::LinkedHashMap;
2
3use crate::index::{IndexEntry, IndexEntryProperty};
4use crate::model::validators::ValidatorContext;
5use crate::model::Model;
6use crate::object_data::Id;
7use crate::object_data::{ObjectValue, ObjectValues};
8use crate::plugins::Plugins;
9use crate::utils::ModelPropertyVectors;
10use crate::HitError;
11use crate::Kernel;
12use crate::{errors::ValidationError, events::FieldListenerRef};
13use crate::{events::Listeners, hit_mod::hit_entry::HitEntry};
14use crate::{helpers::copy_object, index::Index};
15use crate::{hit_mod::helpers::can_move_object, ModelField};
16
17use std::cell::RefCell;
18use std::collections::HashMap;
19use std::rc::Rc;
20
21pub type HitPlugins = Plugins;
22pub type HitKernel = dyn Kernel;
23
24pub(crate) struct ModelIndex {
25    pub map: HashMap<String, Rc<Model>>,
26}
27
28impl ModelIndex {
29    pub fn new() -> Self {
30        ModelIndex {
31            map: HashMap::new(),
32        }
33    }
34}
35
36#[derive(Clone)]
37pub struct Hit {
38    pub index: Index,
39    pub(crate) model_index: Rc<RefCell<ModelIndex>>,
40    pub(crate) plugins: HitPlugins,
41    pub kernel: Rc<HitKernel>,
42    pub(crate) errors: ModelPropertyVectors<ValidationError>,
43    pub(crate) errors_subscriptions: Listeners<Vec<ValidationError>>,
44}
45
46impl Hit {
47    pub fn new(id: &str, model_type: &str, kernel: Rc<HitKernel>) -> Result<Hit, HitError> {
48        Hit::new_with_values(id, kernel, LinkedHashMap::new(), model_type)
49    }
50
51    // imports the data of another hit instance into this hit
52    // used for dependencies
53    pub fn import(&mut self, hit: Hit, parent: IndexEntryProperty) -> Result<(), HitError> {
54        let main_id = hit.get_main_object_id();
55        let get_parent = |x: &IndexEntry| {
56            if x.get_id() == main_id {
57                return Some(parent.clone());
58            }
59            return x.get_parent().clone();
60        };
61
62        for (id, value) in hit.index.index.iter() {
63            if id == main_id {
64                continue;
65            }
66            let value = value.borrow();
67
68            let new_entry = IndexEntry::new_raw(
69                id.clone(),
70                value.data.clone(),
71                get_parent(&value),
72                value.references.clone(),
73            );
74            let model = hit.get_model_or_error(&id)?;
75            self.model_index.borrow_mut().map.insert(id.clone(), model);
76            self.index.index.insert(id.clone(), new_entry);
77        }
78
79        // insert main
80        let main = hit.get(&main_id).unwrap();
81        let model = hit.get_model_or_error(main_id)?;
82
83        self.insert(&model.get_name(), main_id, main.get_data(), parent, None)?;
84        Ok(())
85    }
86
87    pub fn new_with_values(
88        id: &str,
89        kernel: Rc<HitKernel>,
90        values: ObjectValues,
91        model_type: &str,
92    ) -> Result<Hit, HitError> {
93        let mut model_index = ModelIndex::new();
94        let model = kernel.get_model(model_type)?;
95        //TODO : initialize the values in the order defined by the model
96
97        model_index.map.insert(id.to_string(), model);
98        let model_index = Rc::new(RefCell::new(model_index));
99
100        let mut hit = Hit {
101            index: Index::new(id, LinkedHashMap::new())?,
102            model_index: model_index,
103            plugins: kernel.get_plugins(),
104            kernel: kernel,
105            errors: ModelPropertyVectors::new(),
106            errors_subscriptions: Listeners::new(),
107        };
108        for (key, value) in values.iter() {
109            hit.set(id, key, value.clone())?;
110        }
111        hit.validate_all()?;
112        Ok(hit)
113    }
114
115    pub fn contains_key(&self, key: &str) -> bool {
116        return self.model_index.borrow().map.contains_key(key);
117    }
118
119    fn field_is_reference_array(&self, target: &IndexEntryProperty) -> Result<bool, HitError> {
120        let target_model = self.get_model_or_error(&target.id)?;
121
122        let target_model_field = target_model
123            .get_field(&target.property)
124            .ok_or(HitError::PropertyNotFound((&target.property).to_string()))?;
125
126        let target_model_field_borrowed = target_model_field.borrow();
127        if target_model_field_borrowed.is_vec_reference() {
128            Ok(true)
129        } else {
130            Err(HitError::InvalidDataType())
131        }
132    }
133
134    pub fn insert_reference(
135        &mut self,
136        id: &str,
137        target: IndexEntryProperty,
138        before_id: Option<String>,
139    ) -> Result<(), HitError> {
140        // before plugins call
141        for plugin in self.plugins.reference_plugins.clone().iter() {
142            plugin.borrow_mut().on_before_add_reference(
143                self,
144                &id.to_string(),
145                &target,
146                &before_id,
147            )?;
148        }
149
150        let is_valid = self.field_is_reference_array(&target)?;
151
152        if is_valid {
153            self.index
154                .insert_reference(id, target.clone(), before_id.clone())?;
155            for plugin in self.plugins.reference_plugins.clone().iter() {
156                plugin.borrow_mut().on_after_add_reference(
157                    self,
158                    &id.to_string(),
159                    &target,
160                    &before_id,
161                )?;
162            }
163            Ok(())
164        } else {
165            Err(HitError::InvalidReference(id.to_string()))
166        }
167    }
168
169    pub fn remove_reference(
170        &mut self,
171        id: &str,
172        parent: IndexEntryProperty,
173    ) -> Result<(), HitError> {
174        // before plugins call
175        for plugin in self.plugins.reference_plugins.clone().iter() {
176            plugin
177                .borrow_mut()
178                .on_before_remove_reference(self, &id.to_string(), &parent)?;
179        }
180
181        // check in model that this property exists and is of a valid type
182        let target_model = self.get_model_or_error(&parent.id)?;
183        let target_property = target_model
184            .get_field(&parent.property)
185            .ok_or(HitError::PropertyNotFound((&parent.property).into()))?;
186        let target_property = target_property.borrow();
187        if target_property.is_vec_reference() {
188            self.index.remove_reference(id, parent.clone())?;
189
190            for plugin in self.plugins.reference_plugins.clone().iter() {
191                plugin
192                    .borrow_mut()
193                    .on_after_remove_reference(self, &id.to_string(), &parent)?;
194            }
195            Ok(())
196        } else {
197            Err(HitError::InvalidDataType())
198        }
199    }
200
201    pub fn move_reference(
202        &mut self,
203        id: &str,
204        target: IndexEntryProperty,
205        before_id: Option<Id>,
206    ) -> Result<(), HitError> {
207        // before plugins call
208        for plugin in self.plugins.reference_plugins.clone().iter() {
209            plugin
210                .borrow_mut()
211                .on_before_remove_reference(self, &id.to_string(), &target)?;
212        }
213
214        // check in model that this property exists and is of a valid type
215        let target_model = self.get_model_or_error(&target.id)?;
216        let target_property = target_model
217            .get_field(&target.property)
218            .ok_or(HitError::PropertyNotFound((&target.property).into()))?;
219        let target_property = target_property.borrow();
220        if target_property.is_vec_reference() {
221            self.index
222                .move_reference(id, target.clone(), before_id.clone())?;
223
224            for plugin in self.plugins.reference_plugins.clone().iter() {
225                plugin
226                    .borrow_mut()
227                    .on_after_remove_reference(self, &id.to_string(), &target)?;
228            }
229            Ok(())
230        } else {
231            Err(HitError::InvalidDataType())
232        }
233    }
234
235    pub fn get_references(&self, id: &str) -> Result<Vec<IndexEntryProperty>, HitError> {
236        self.index.get_references(id)
237    }
238
239    pub fn find_references_recursive(
240        &self,
241        id: &str,
242    ) -> Result<(HashMap<String, Vec<IndexEntryProperty>>, Vec<String>), HitError> {
243        self.index.find_references_recursive(id)
244    }
245
246    pub fn remove_object(&mut self, id: &str) -> Result<Vec<String>, HitError> {
247        let entry = self.index.get(id).ok_or(HitError::IDNotFound(
248            id.to_string(),
249            "remove_object entry".to_string(),
250        ))?;
251        let model = self.get_model(id).ok_or(HitError::IDNotFound(
252            id.to_string(),
253            "remove_object model".to_string(),
254        ))?;
255
256        // before plugins call
257        for plugin in self.plugins.delete_plugins.clone().iter() {
258            plugin.borrow_mut().on_before_delete_entry(
259                &HitEntry {
260                    entry: entry.clone(),
261                    model: model.clone(),
262                },
263                self,
264            )?;
265        }
266
267        let id_list = self.index.remove_object(id)?;
268
269        // after plugins call
270        for plugin in self.plugins.delete_plugins.clone().iter() {
271            plugin.borrow_mut().on_after_delete_entry(
272                &HitEntry {
273                    entry: entry.clone(),
274                    model: model.clone(),
275                },
276                self,
277            )?;
278        }
279
280        //remove model indexes of the deleted objects
281        for id in id_list.iter() {
282            let mut model_index = self.model_index.borrow_mut();
283            model_index.map.remove(id);
284        }
285        Ok(id_list)
286    }
287
288    pub fn can_move_object(
289        &self,
290        id: &str,
291        target_id: &str,
292        target_model: &str,
293        property: &str,
294    ) -> Result<(), HitError> {
295        can_move_object(&self, id, target_id, target_model, property)
296    }
297
298    pub fn move_object(
299        &mut self,
300        id: &str,
301        target: IndexEntryProperty,
302        before_id: Option<String>,
303    ) -> Result<(), HitError> {
304        //check destination is allowed
305        let target_model = self.get_model_or_error(&target.id)?;
306        if !self.model_index.borrow().map.contains_key(id) {
307            return Err(HitError::IDNotFound(id.into(), "move_object".into()));
308        }
309        let original_parent = self
310            .get_parent(id)
311            .ok_or(HitError::CannotMoveRootObject())?;
312
313        for plugin in self.plugins.plugins.iter() {
314            plugin.borrow_mut().on_before_move_subobject(
315                id.clone(),
316                target.clone(),
317                before_id.clone(),
318                &self,
319            )?;
320        }
321
322        self.can_move_object(id, &target.id, target_model.get_name(), &target.property)?;
323        self.index
324            .move_object(id, target.clone(), before_id.clone())?;
325        let plugins = { self.plugins.plugins.clone() };
326        for plugin in plugins.iter() {
327            plugin.borrow_mut().on_after_move_subobject(
328                id.clone(),
329                target.clone(),
330                original_parent.clone(),
331                before_id.clone(),
332                self,
333            )?;
334        }
335        Ok(())
336    }
337
338    pub fn copy_object(
339        &mut self,
340        id: Id,
341        target: IndexEntryProperty,
342        before_id: Option<String>,
343    ) -> Result<Id, HitError> {
344        let target_model = self.get_model_or_error(&target.id)?;
345        if !self.model_index.borrow().map.contains_key(&id) {
346            return Err(HitError::IDNotFound(id.into(), "copy_object".into()));
347        }
348        self.can_move_object(&id, &target.id, target_model.get_name(), &target.property)?;
349
350        let id = copy_object(self, &id, target, before_id)?;
351        return Ok(id);
352    }
353
354    pub fn get_model(&self, id: &str) -> Option<Rc<Model>> {
355        match self.model_index.borrow().map.get(id) {
356            Some(model) => Some(model.clone()),
357            None => None,
358        }
359    }
360
361    fn get_model_or_error(&self, id: &str) -> Result<Rc<Model>, HitError> {
362        self.get_model(id)
363            .ok_or(HitError::IDNotFound(id.into(), "get_model".into()))
364    }
365    /*
366    fn get_model_field_or_error(
367        &self,
368        id: &str,
369        property: &str,
370    ) -> Result<&ModelFieldRef, HitError> {
371        let model = self.get_model_or_error(id)?;
372        let a = model
373            .get_field(property)
374            .ok_or(HitError::PropertyNotFound(property.into()));
375        return a;
376    } */
377
378    pub fn get(&self, id: &str) -> Option<HitEntry> {
379        let index_entry = self.index.get(id)?;
380        let model = self.model_index.borrow();
381        let model = model.map.get(id)?;
382        Some(HitEntry {
383            entry: index_entry,
384            model: model.clone(),
385        })
386    }
387
388    pub fn get_value(&self, id: &str, property: &str) -> Option<ObjectValue> {
389        self.index.get_value(id, property)
390    }
391
392    pub fn set(&mut self, id: &str, property: &str, value: ObjectValue) -> Result<(), HitError> {
393        let entry = self
394            .get(id)
395            .ok_or(HitError::IDNotFound(id.to_string(), "set".into()))?;
396        let model_field = entry
397            .model
398            .get_field(property)
399            .ok_or(HitError::PropertyNotFound(property.to_string()))?;
400
401        let old_value = self.get_value(id, property);
402
403        for plugin in self.plugins.plugins.iter() {
404            plugin.borrow_mut().on_before_set_value(
405                IndexEntryProperty {
406                    id: id.into(),
407                    property: property.into(),
408                },
409                &value,
410                &old_value,
411                &self,
412            )?;
413        }
414
415        //does the field accept the object value
416        if !model_field.borrow().accepts_for_set(
417            &value,
418            &ValidatorContext {
419                id: id,
420                property: property,
421                index: Rc::new(self),
422            },
423        ) {
424            return Err(HitError::InvalidDataType());
425        }
426
427        self.index.set_value(id, property, value.clone())?;
428
429        for plugin in { self.plugins.plugins.clone() }.iter() {
430            plugin.borrow_mut().on_after_set_value(
431                IndexEntryProperty {
432                    id: id.into(),
433                    property: property.into(),
434                },
435                &value,
436                &old_value,
437                self,
438            )?;
439        }
440
441        self._validate_field(model_field, id, property, value)?;
442
443        Ok(())
444    }
445
446    fn validate_inserted_values(
447        &mut self,
448        new_object_model: &Rc<Model>,
449        id: &str,
450        values: &ObjectValues,
451    ) -> Result<ObjectValues, HitError> {
452        // put the data in the correct field order, initialize null data
453        // and validate the data of the new object
454        let mut ordered_values: ObjectValues = LinkedHashMap::new();
455        for (property, model_field) in new_object_model.fields.iter() {
456            //does the field accept the object value
457            match values.get(property) {
458                Some(value) => {
459                    match value {
460                        ObjectValue::Null => {}
461                        _ => {
462                            if !model_field.borrow().accepts_for_set(
463                                &value,
464                                &ValidatorContext {
465                                    id: id,
466                                    property: property,
467                                    index: Rc::new(self),
468                                },
469                            ) {
470                                return Err(HitError::InvalidDataType());
471                            }
472                        }
473                    };
474                    ordered_values.insert(property.to_string(), value.clone());
475                }
476                None => {
477                    ordered_values.insert(property.to_string(), ObjectValue::Null);
478                }
479            }
480        }
481        Ok(ordered_values)
482    }
483
484    pub fn insert(
485        &mut self,
486        model_type: &str,
487        id: &str,
488        values: ObjectValues,
489        parent: IndexEntryProperty,
490        before_id: Option<String>,
491    ) -> Result<(), HitError> {
492        let new_object_model = self
493            .kernel
494            .get_model(&model_type.to_string())
495            .map_err(|_| HitError::ModelDoesNotExist(model_type.to_string()))?;
496
497        // before_add_entry hook
498        for plugin in self.get_plugins().plugins.iter() {
499            plugin.borrow_mut().on_before_add_entry(
500                new_object_model.clone(),
501                &id,
502                values.clone(),
503                parent.clone(),
504                &before_id,
505                &self,
506            )?;
507        }
508
509        let target_model = self.get_model_or_error(&parent.id)?;
510
511        // verify that the model field exists and is of the right type
512        let field = target_model
513            .get_field(&parent.property)
514            .ok_or(HitError::PropertyNotFound(parent.property.clone()))?;
515        let field = field.borrow();
516        if !field.is_vec_subobject() {
517            return Err(HitError::CannotInsertObjectInThisDataType());
518        }
519        // check if model is authorized
520        if !field.accepts_model(&new_object_model) {
521            return Err(HitError::ModelNotAllowed(model_type.into()));
522        }
523
524        let values = self.validate_inserted_values(&new_object_model, id, &values)?;
525        // update the data
526        self.index
527            .insert(id, values.clone(), parent.clone(), before_id.clone())?;
528        self.model_index
529            .borrow_mut()
530            .map
531            .insert(id.to_string(), new_object_model.clone());
532
533        // after_add_entry hook
534        for plugin in { self.get_plugins().plugins.clone() }.iter() {
535            plugin.borrow_mut().on_after_add_entry(
536                new_object_model.clone(),
537                &id,
538                values.clone(),
539                parent.clone(),
540                &before_id,
541                self,
542            )?;
543        }
544
545        Ok(())
546    }
547
548    pub fn get_plugins(&self) -> &HitPlugins {
549        return &self.plugins;
550    }
551    pub fn get_main_object_id(&self) -> &Id {
552        return &self.index.get_main_object_id();
553    }
554
555    pub fn subscribe_field(
556        &self,
557        id: &str,
558        field: &str,
559        listener: FieldListenerRef<ObjectValue>,
560    ) -> Result<String, HitError> {
561        let model = self.get_model_or_error(id)?;
562        model
563            .get_field(field)
564            .ok_or(HitError::PropertyNotFound(field.to_string()))?;
565
566        match self.index.get(id) {
567            Some(entry) => {
568                {
569                    entry.borrow_mut().add_listener(field, listener.clone());
570                }
571
572                let listener_id = {
573                    let borrow = listener.borrow();
574                    borrow.get_unique_id().to_string()
575                };
576                Ok(listener_id)
577            }
578            None => Err(HitError::IDNotFound(
579                id.to_string(),
580                "subscribe_field".into(),
581            )),
582        }
583    }
584
585    pub fn unsubscribe_field(
586        &self,
587        id: &str,
588        field: &str,
589        listener_id: &str,
590    ) -> Result<(), HitError> {
591        match self.index.get(id) {
592            Some(entry) => {
593                entry.borrow_mut().remove_listener(field, listener_id)?;
594                Ok(())
595            }
596            None => Err(HitError::IDNotFound(
597                id.to_string(),
598                "unsubscribe_field".into(),
599            )),
600        }
601    }
602
603    pub fn get_parent(&self, id: &str) -> Option<IndexEntryProperty> {
604        self.get(id)?.get_parent()
605    }
606
607    pub fn get_parent_index(&self, id: &str) -> Option<usize> {
608        let parent = self.get_parent(id)?;
609        match self.get_value(&parent.id, &parent.property)? {
610            ObjectValue::VecSubObjects(parent_value) => {
611                parent_value.iter().position(|r| r.id == id)
612            }
613            _ => None,
614        }
615    }
616
617    fn _validate_field(
618        &mut self,
619        model_field: &Rc<RefCell<dyn ModelField>>,
620        id: &str,
621        property: &str,
622        value: ObjectValue,
623    ) -> Result<(), HitError> {
624        let validation_errors = model_field.borrow().validate(
625            &value,
626            &ValidatorContext {
627                id: &id.to_string(),
628                property: &property.to_string(),
629                index: Rc::new(self),
630            },
631        )?;
632        self.errors.delete(id, property);
633        match validation_errors.clone() {
634            None => {}
635            Some(validation_errors) => {
636                for error in validation_errors.into_iter() {
637                    self.errors.add(id, property, error);
638                }
639            }
640        }
641
642        // dispatch event
643
644        self.errors_subscriptions.dispatch_value(
645            &Self::get_validation_subscription_key(id, property),
646            &{
647                match validation_errors {
648                    Some(validation_errors) => validation_errors,
649                    None => vec![],
650                }
651            },
652        );
653
654        Ok(())
655    }
656
657    pub fn validate_field(&mut self, id: &str, property: &str) -> Result<(), HitError> {
658        let model = self.get_model_or_error(id)?;
659        let model_field = model
660            .get_field(property)
661            .ok_or(HitError::PropertyNotFound(property.to_string()))?;
662
663        let value = self.get_value(id, property);
664        self._validate_field(
665            model_field,
666            id,
667            property,
668            value.or(Some(ObjectValue::Null)).unwrap(),
669        )?;
670        Ok(())
671    }
672
673    fn get_validation_subscription_key(id: &str, field: &str) -> String {
674        format!("{}{}", id, field)
675    }
676    pub fn get_validation_errors(&self, id: &str, field: &str) -> Option<&Vec<ValidationError>> {
677        self.errors.get(id, field)
678    }
679    pub fn subscribe_field_validation(
680        &mut self,
681        id: &str,
682        field: &str,
683        listener: FieldListenerRef<Vec<ValidationError>>,
684    ) {
685        self.errors_subscriptions
686            .insert(&Self::get_validation_subscription_key(id, field), listener);
687    }
688
689    pub fn unsubscribe_field_validation(
690        &mut self,
691        id: &str,
692        field: &str,
693        listener_id: &str,
694    ) -> Result<(), HitError> {
695        self.errors_subscriptions.remove(
696            &Self::get_validation_subscription_key(id, field),
697            listener_id,
698        )
699    }
700
701    pub(crate) fn validate_all(&mut self) -> Result<(), HitError> {
702        let model_index = self.model_index.borrow().map.clone();
703
704        for (id, model) in model_index.iter() {
705            for (field_name, _field) in model.get_fields().iter() {
706                let model_field = model
707                    .get_field(field_name)
708                    .ok_or(HitError::PropertyNotFound(field_name.to_string()))?;
709                let value = self
710                    .get_value(&id, field_name)
711                    .or(Some(ObjectValue::Null))
712                    .unwrap();
713                self._validate_field(model_field, &id, field_name, value)?;
714            }
715        }
716        Ok(())
717    }
718}