Example 5: Merge

  • file format 6
  • Rust SDK 1.0 preview

Needs the Rust SDK

Merge two packs that disagree about one entity, with the default strategy and with union.

05_merge.rsrust
// Merge two packs and choose how a conflict between two versions of
// one entity is settled.
use plxi_sdk::{
    merge, write, MergeOptions, MergeStrategy, OpenOptions, Pack, Record,
};

type Result<T> = std::result::Result<T, plxi_sdk::Error>;

fn pack(lines: &[&str]) -> Result<Vec<u8>> {
    let records: Vec<Record> = lines
        .iter()
        .map(|l| Record::from_json_line(l))
        .collect::<Result<_>>()?;
    write(&records, None)
}

fn name_of_e1(bytes: Vec<u8>) -> Result<Option<String>> {
    let pack = Pack::from_bytes(bytes, OpenOptions::default())?;
    for record in pack.records() {
        let record = record?;
        if let Some(e) = record.as_entity() {
            if e.id == "e1" {
                return Ok(e.name.map(str::to_string));
            }
        }
    }
    Ok(None)
}

fn main() -> Result<()> {
    let a = pack(&[
        r#"{"k":"ent","id":"e1","t":"Person","salience":0.5}"#,
        r#"{"k":"ent","id":"e2","t":"Person"}"#,
        r#"{"k":"rel","src":"e1","tgt":"e2","kind":"knows"}"#,
    ])?;
    let b = pack(&[
        r#"{"k":"ent","id":"e1","t":"Person","salience":0.75,"name":"B"}"#,
        r#"{"k":"ent","id":"e3","t":"Person"}"#,
        r#"{"k":"rel","src":"e1","tgt":"e3","kind":"knows"}"#,
    ])?;

    // Default strategy: the incoming entity wins only with a strictly
    // greater salience. 0.75 > 0.5, so pack b's e1 is taken.
    let default = MergeOptions::default();
    assert_eq!(default.strategy, MergeStrategy::HigherSalience);
    let (merged, report) = merge(&[&a, &b], &default)?;
    assert_eq!((report.records_inserted, report.conflicts), (5, 1));
    assert_eq!(name_of_e1(merged)?, Some("B".to_string()));
    println!("{}", report.to_json());

    // `Union` keeps the record that was there first.
    let union = MergeOptions::with_strategy(MergeStrategy::Union);
    let (merged, _) = merge(&[&a, &b], &union)?;
    assert_eq!(name_of_e1(merged)?, None);

    // Strategies have stable names, for configuration files.
    assert_eq!(MergeStrategy::Latest.as_str(), "latest");
    let manual = MergeStrategy::from_name("manual");
    assert_eq!(manual, Some(MergeStrategy::Manual));
    assert_eq!(MergeStrategy::from_name("newest"), None);
    Ok(())
}
Output
{"records_inserted":5,"records_updated":1,"records_skipped":0,"stubs_resolved":0,"conflicts":1,"sections_merged":0,"sections_deduped":0}

Ran with cargo run --example 05_merge · exit status 0

Explained in: Merge packs

Sections