1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use hdk::prelude::*;
/// Generic structure to hold all versions of an entry
#[derive(Serialize, Deserialize, Debug)]
pub struct EntryWithAllVersions<T> {
pub current_entry: T,
pub other_versions: Vec<T>,
}
/// Generic utility function to get all versions of an entry by following the update chain
/// both backwards (older versions) and forwards (newer versions)
pub fn get_entry_all_versions<T, F>(
hash: ActionHash,
entry_converter: F,
) -> ExternResult<EntryWithAllVersions<T>>
where
F: Fn(&ActionHash) -> ExternResult<T>,
{
let details = hdk::prelude::get_details(hash.clone(), GetOptions::default())?;
if let Some(Details::Record(record_details)) = details {
// Get the current version
let current_entry = entry_converter(&hash)?;
// Collect all versions - both older and newer
let mut older_versions = Vec::new();
let mut newer_versions = Vec::new();
// First, check if this record is itself an update and get older versions
let current_record_details = record_details.clone();
if let Action::Update(update_action) = current_record_details.record.action() {
// This is an update, so there are older versions
let mut prev_hash = update_action.original_action_address.clone();
// Follow the prev_action chain backwards
while let Some(Details::Record(prev_record_details)) =
hdk::prelude::get_details(prev_hash.clone(), GetOptions::default())?
{
let prev_entry = entry_converter(&prev_hash)?;
older_versions.push(prev_entry);
// Check if this previous record is also an update
if let Action::Update(prev_update_action) = prev_record_details.record.action() {
prev_hash = prev_update_action.original_action_address.clone();
} else {
break; // Reached the original record
}
}
// Reverse to get chronological order (oldest first)
older_versions.reverse();
}
// Now follow the update chain forward for newer versions
let mut current_details = record_details;
// Follow the update chain iteratively
loop {
if !current_details.updates.is_empty() {
if let Some(first_update) = current_details.updates.first() {
// Get the details of the first (and expected only) update
let update_hash = first_update.action_address();
let updated_entry = entry_converter(update_hash)?;
newer_versions.push(updated_entry);
// Get details of the updated record to check for further updates
if let Some(Details::Record(next_record_details)) =
hdk::prelude::get_details(update_hash.clone(), GetOptions::default())?
{
current_details = next_record_details;
} else {
break;
}
} else {
break; // No more updates
}
} else {
break; // No updates
}
}
// Combine all versions in chronological order
let mut all_versions = Vec::new();
all_versions.extend(older_versions);
all_versions.extend(newer_versions);
return Ok(EntryWithAllVersions {
current_entry,
other_versions: all_versions,
});
}
Err(wasm_error!("No entry found"))
}