I might try the serde approach of @hpeebles, looks pretty neat. Thanks for the share!
Of course not a comparable to the experience as above examples, I’m a Rust newbie and it’s probably slower but, for what is worth, with candid, what I do, if interesting, is having a dedicated module (juno/src/satellite/src/upgrade at main · buildwithjuno/juno · GitHub) and types for the migration.
In my post_upgrade I do
#[post_upgrade]
fn post_upgrade() {
let (upgrade_stable,): (UpgradeStableState,) = stable_restore().unwrap();
let stable = StableState::from(&upgrade_stable);
I deserialize to a type that represent previous types and that is only use for the migration (UpgradeStableState
) and afterwards I parse it to the effective new types of the memory (StableState
).
In that particular “upgrade” module I got a type and the implementation.
e.g. here I modified a type of my stable memory from String
to Option<String>
so I had to map.
impl From<&UpgradeStableState> for StableState {
fn from(state: &UpgradeStableState) -> Self {
let mut custom_domains = HashMap::new();
for (domain_name, custom_domain) in state.storage.custom_domains.clone().into_iter() {
custom_domains.insert(
domain_name,
CustomDomain {
updated_at: custom_domain.updated_at,
created_at: custom_domain.created_at,
bn_id: Some(custom_domain.bn_id), // <---- this one changed
},
);
}
StableState {
controllers: state.controllers.clone(),
db: state.db.clone(),
storage: StorageStableState {
assets: state.storage.assets.clone(),
rules: state.storage.rules.clone(),
config: StorageConfig::default(),
custom_domains,
},
}
}
}
Again, just sharing in case interesting.