On this page· 4

Compare packs

  • file format 6
  • Rust SDK 1.0 preview

Goal: list what changed between a before pack and an after pack.

Steps

  1. 1. Open both packs.
  2. 2. Call diff(&before, &after).
  3. 3. Read added, removed and changed, or print to_json().

Needs the Rust SDK

diff.rsrust
// Compare two packs record by record.
use plxi_sdk::{diff, write, OpenOptions, Pack, Record};

fn open(lines: &[&str]) -> Result<Pack, plxi_sdk::Error> {
    let records: Vec<Record> = lines
        .iter()
        .map(|l| Record::from_json_line(l))
        .collect::<Result<_, _>>()?;
    Pack::from_bytes(write(&records, None)?, OpenOptions::default())
}

fn main() -> Result<(), plxi_sdk::Error> {
    let before = open(&[
        r#"{"k":"ent","id":"e1","t":"P","name":"A"}"#,
        r#"{"k":"ent","id":"e2","t":"P"}"#,
        r#"{"k":"rel","src":"e1","tgt":"e2","kind":"knows"}"#,
    ])?;
    let after = open(&[
        r#"{"k":"ent","id":"e1","t":"P","name":"B"}"#,
        r#"{"k":"ent","id":"e3","t":"P"}"#,
        r#"{"k":"rel","src":"e1","tgt":"e2","kind":"knows"}"#,
    ])?;

    let d = diff(&before, &after)?;
    let e3 = r#"{"k":"ent","v":1,"id":"e3","t":"P","stub":false}"#;
    let e2 = r#"{"k":"ent","v":1,"id":"e2","t":"P","stub":false}"#;
    assert_eq!(d.added, [e3]);
    assert_eq!(d.removed, [e2]);
    assert_eq!(d.changed.len(), 1);
    assert_eq!(d.changed[0].key, ("ent".to_string(), "e1".to_string()));
    assert!(!d.is_empty());
    println!("{}", d.to_json());

    // A pack compared with itself has no differences.
    assert!(diff(&before, &before)?.is_empty());
    Ok(())
}
Output
{"added":["{\"k\":\"ent\",\"v\":1,\"id\":\"e3\",\"t\":\"P\",\"stub\":false}"],"removed":["{\"k\":\"ent\",\"v\":1,\"id\":\"e2\",\"t\":\"P\",\"stub\":false}"],"changed":[{"key":["ent","e1"],"before":"{\"k\":\"ent\",\"v\":1,\"id\":\"e1\",\"t\":\"P\",\"name\":\"A\",\"stub\":false}","after":"{\"k\":\"ent\",\"v\":1,\"id\":\"e1\",\"t\":\"P\",\"name\":\"B\",\"stub\":false}"}],"duplicate_keys":[],"appendix":{"added":[],"removed":[],"changed":[]}}

Ran with cargo run --example 06_diff · exit status 0

Table 1. Members of a diff: 5
MemberHolds
addedrecord lines whose key is only in the second pack
removedrecord lines whose key is only in the first pack
changedone entry per key in both packs whose identity forms differ: key, before, after
duplicate_keyskeys that occur more than once in either pack; such a key appears here and nowhere else
appendixlists of section indexes: added, removed, changed

Three more cases

Table 2. Diff cases in the conformance corpus: 3
CaseInputResult
diff-member-order-onlythe same record with members in another order and 1.0 written as 1.00every list empty
diff-duplicate-keysthe after pack holds ent e5 twiceduplicate_keys holds ["ent","e5"], and nothing else
diff-appendix-section-changedone byte changed in appendix section 1appendix.changed holds [1]

Things to know

  • Records are compared in identity form. Member order, whitespace and number spelling alone are never a difference.
  • Diff has a direction: the first pack is before, the second is after.
  • Appendix sections are matched by position and compared by type and CRC32C. A section inserted at index 0 makes every later index read as changed, and the diff names section indexes, not rows.
  • Diff does not check that relations still point at entities. In the example, the after pack keeps a relation to e2, which was removed.
  • Both packs are opened first, so both were verified unless opened with no_verify().

Reference

Sections