Skip to main content

dotloom_engine/
migrate.rs

1//! Plugin entity property migrations (type version upgrades).
2
3use dotloom_document::{Document, EntityId, PropValue};
4
5use crate::registry::Registry;
6
7/// Upgrade plugin entities whose `type_version` is older than the registered
8/// definition, applying the definition's migration steps in order. Entities written
9/// by a newer version are left untouched (they evaluate as read-only).
10pub fn migrate_entities(doc: &mut Document, registry: &Registry) -> Vec<(EntityId, u32, u32)> {
11    let mut done = Vec::new();
12    let ids: Vec<EntityId> = doc.order().to_vec();
13    for id in ids {
14        let Some(e) = doc.entity(id) else { continue };
15        let Some(entry) = registry.get(&e.type_id) else { continue };
16        let def = &entry.compiled.def;
17        if e.type_version >= def.version {
18            continue;
19        }
20        let from = e.type_version;
21        let mut props = e.props.clone();
22        let mut v = from;
23        while v < def.version {
24            if let Some(step) = def.migrations.iter().find(|m| m.from == v) {
25                for (old, new) in &step.rename {
26                    if let Some(val) = props.remove(old) {
27                        props.insert(new.clone(), val);
28                    }
29                }
30                for (k, val) in &step.set {
31                    if !props.contains_key(k)
32                        && let Ok(pv) = serde_json::from_value::<PropValue>(val.clone())
33                    {
34                        props.insert(k.clone(), pv);
35                    }
36                }
37                for k in &step.remove {
38                    props.remove(k);
39                }
40            }
41            v += 1;
42        }
43        if let Some(e) = doc.entity_mut(id) {
44            e.props = props;
45            e.type_version = def.version;
46            done.push((id, from, def.version));
47        }
48    }
49    done
50}