hit_data/hit_mod/helpers/
hit_copy_helper.rs

1use std::collections::HashMap;
2
3use crate::{Hit, HitError, Id, IndexEntryProperty, ObjectValue, ObjectValues, Reference};
4
5fn uuid() -> String {
6    (0..10)
7        .map(|_| (0x20u8 + (rand::random::<f32>() * 96.0) as u8) as char)
8        .collect()
9}
10
11fn _copy_object(
12    hit: &mut Hit,
13    id: &Id,
14    target: IndexEntryProperty,
15    before_id: Option<String>,
16    references_to_update: &mut Vec<ReferenceToUpdate>,
17    updated_ids: &mut HashMap<Id, Id>,
18) -> Result<Id, HitError> {
19    let new_id = uuid();
20    let entry = hit.get(id).ok_or(HitError::IDNotFound(id.to_string(), "copy_object entry".to_string()))?;
21    let model = hit
22        .get_model(id)
23        .ok_or(HitError::ModelDoesNotExist(id.into()))?;
24    let mut values = ObjectValues::new();
25
26    // copy simple values
27    for (field_name, _field) in model.get_fields().iter() {
28        let value = entry.get(field_name);
29        match value {
30            crate::ObjectValue::Reference(r) => {
31                references_to_update.push(ReferenceToUpdate {
32                    target: IndexEntryProperty {
33                        id: new_id.clone(),
34                        property: field_name.clone(),
35                    },
36                    reference: r.id,
37                    vec: false,
38                });
39            }
40            crate::ObjectValue::VecReference(refs) => {
41                for r in refs.iter() {
42                    references_to_update.push(ReferenceToUpdate {
43                        target: IndexEntryProperty {
44                            id: new_id.clone(),
45                            property: field_name.clone(),
46                        },
47                        reference: r.id.clone(),
48                        vec: true,
49                    });
50                }
51            }
52            crate::ObjectValue::SubObject(_) => {}
53            crate::ObjectValue::VecSubObjects(_) => {}
54            _ => {
55                values.insert(field_name.to_string(), value.clone());
56            }
57        }
58    }
59
60    hit.insert(
61        entry.get_model().get_name(),
62        &new_id,
63        values,
64        target,
65        before_id,
66    )?;
67
68    updated_ids.insert(id.clone(), new_id.clone());
69
70    // copy subobjects
71    for (field_name, _field) in model.get_fields().iter() {
72        let value = entry.get(field_name);
73        match value {
74            crate::ObjectValue::Reference(_) => {}
75            crate::ObjectValue::VecReference(_) => {}
76            crate::ObjectValue::SubObject(subobject) => {
77                _copy_object(
78                    hit,
79                    &subobject.id,
80                    IndexEntryProperty {
81                        id: new_id.clone(),
82                        property: field_name.clone(),
83                    },
84                    None,
85                    references_to_update,
86                    updated_ids,
87                )?;
88            }
89            crate::ObjectValue::VecSubObjects(subobjects) => {
90                for subobject in subobjects.iter() {
91                    _copy_object(
92                        hit,
93                        &subobject.id,
94                        IndexEntryProperty {
95                            id: new_id.clone(),
96                            property: field_name.clone(),
97                        },
98                        None,
99                        references_to_update,
100                        updated_ids,
101                    )?;
102                }
103            }
104            _ => {}
105        }
106    }
107    Ok(new_id)
108}
109
110struct ReferenceToUpdate {
111    target: IndexEntryProperty,
112    reference: Id,
113    vec: bool,
114}
115
116fn get_updated_id(id: Id, updated_ids: &HashMap<Id, Id>) -> Id {
117    match updated_ids.get(&id.clone()) {
118        Some(updated_id) => updated_id.clone(),
119        None => id,
120    }
121}
122
123pub fn copy_object(
124    hit: &mut Hit,
125    id: &Id,
126    target: IndexEntryProperty,
127    before_id: Option<String>,
128) -> Result<Id, HitError> {
129    let mut references_to_update: Vec<ReferenceToUpdate> = vec![];
130    let mut updated_ids: HashMap<Id, Id> = HashMap::new();
131    let new_id = {
132        _copy_object(
133            hit,
134            id,
135            target,
136            before_id,
137            &mut references_to_update,
138            &mut updated_ids,
139        )?
140    };
141
142    // reproduce inner references, leave the others
143    for reference in references_to_update.iter() {
144        let updated_id = get_updated_id(reference.reference.clone(), &updated_ids);
145        if reference.vec {
146            hit.insert_reference(&updated_id, reference.target.clone(), None)?;
147        } else {
148            hit.set(
149                &reference.target.id,
150                &reference.target.property,
151                ObjectValue::Reference(Reference { id: updated_id }),
152            )?;
153        }
154    }
155
156    Ok(new_id)
157}