lix 0.17.1

Embeddable version control for apps and AI agents.
Documentation
//! These archives are frozen old build outputs, never regenerated by this test.
use futures_util::io::Cursor;
use lix::{CreateBranchOptions, MergeBranchOptions, SwitchBranchOptions, Value, open_lix};

const CSV: &[u8] = include_bytes!("fixtures/plugin-api/legacy-v2/plugin_csv.lixplugin");

#[tokio::test]
async fn frozen_legacy_v2_archive_edits_merges_and_reopens() {
    archive_edits_merges_and_reopens(CSV).await;
}

#[tokio::test]
async fn frozen_v2_archive_edits_merges_and_reopens() {
    archive_edits_merges_and_reopens(include_bytes!(
        "fixtures/plugin-api/v2/plugin_csv.lixplugin"
    ))
    .await;
}

async fn archive_edits_merges_and_reopens(archive: &[u8]) {
    let lix = open_lix().await.unwrap();
    lix.execute(
        "INSERT INTO lix_file (path, content) VALUES ('/.lix/plugins/plugin_csv.lixplugin', $1)",
        &[Value::Blob(archive.to_vec().into())],
    )
    .await
    .unwrap();
    lix.execute(
        "INSERT INTO lix_file (path, content) VALUES ('/people.csv', $1)",
        &[Value::Blob(b"name,age\nAda,36\n".to_vec().into())],
    )
    .await
    .unwrap();
    // Both detection and a subsequent file update must call the frozen guest.
    lix.execute(
        "UPDATE lix_file SET content = $1 WHERE path = '/people.csv'",
        &[Value::Blob(b"name,age\nAda,37\n".to_vec().into())],
    )
    .await
    .unwrap();
    let rows = lix
        .execute("SELECT id FROM csv_row ORDER BY order_key", &[])
        .await
        .unwrap();
    assert_eq!(rows.rows().len(), 2);
    let id = rows.rows()[1].values()[0].clone();
    let main = lix.active_branch_id().await.unwrap();
    let draft = lix
        .create_branch(CreateBranchOptions {
            id: None,
            name: "Compatibility".into(),
            from_commit_id: None,
        })
        .await
        .unwrap();
    lix.switch_branch(SwitchBranchOptions {
        branch_id: draft.id.clone(),
    })
    .await
    .unwrap();
    lix.execute(
        "UPDATE csv_row SET cells = $1 WHERE id = $2",
        &[
            Value::Jsonb(serde_json::json!(["Ada Lovelace", "37"]).into()),
            id.clone(),
        ],
    )
    .await
    .unwrap();
    lix.switch_branch(SwitchBranchOptions { branch_id: main })
        .await
        .unwrap();
    lix.execute(
        "UPDATE csv_row SET cells = $1 WHERE id = $2",
        &[
            Value::Jsonb(serde_json::json!(["Ada", "38"]).into()),
            id.clone(),
        ],
    )
    .await
    .unwrap();
    lix.merge_branch(MergeBranchOptions {
        source_branch_id: draft.id,
    })
    .await
    .unwrap();
    let file = lix
        .execute(
            "SELECT content FROM lix_file WHERE path = '/people.csv'",
            &[],
        )
        .await
        .unwrap();
    assert_eq!(
        file.rows()[0].values()[0],
        Value::Blob(b"name,age\nAda Lovelace,38\n".to_vec().into())
    );
    let mut snapshot = Vec::new();
    lix.export_snapshot().write_to(&mut snapshot).await.unwrap();
    lix.close().await.unwrap();
    let reopened = open_lix()
        .from_snapshot(Cursor::new(snapshot))
        .await
        .unwrap();
    reopened
        .execute(
            "UPDATE csv_row SET cells = $1 WHERE id = $2",
            &[
                Value::Jsonb(serde_json::json!(["Ada Lovelace", "39"]).into()),
                id,
            ],
        )
        .await
        .unwrap();
    let file = reopened
        .execute(
            "SELECT content FROM lix_file WHERE path = '/people.csv'",
            &[],
        )
        .await
        .unwrap();
    assert_eq!(
        file.rows()[0].values()[0],
        Value::Blob(b"name,age\nAda Lovelace,39\n".to_vec().into())
    );
    reopened.close().await.unwrap();
}