hit_data/hit_mod/helpers/
hit_copy_helper.rs1use 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 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 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 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}