assemblage_view 0.1.0

Linearized View Model and Bindings for AssemblageDB
Documentation
#![cfg(feature = "assemblage-broadcast-integration-tests")]
use assemblage_db::{
    broadcast::Broadcast,
    data::{Id, Layout, Node},
    tx, Db,
};
use assemblage_kv::{storage::MemoryStorage, test};
use assemblage_view::{
    model::{Block, Section, Span, Subsection, Tile},
    DbView, Result,
};
use std::{collections::BTreeSet, iter::FromIterator};

#[cfg(target_arch = "wasm32")]
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);

test! {
    async fn broadcast_tile(storage) -> Result<()> {
        let db = Db::open(storage).await?;
        let root_id = Id::root();
        let (id1, id2, broadcast, last_updated) = {
            let text1 = Node::text("foo");
            let id1 = tx!(|db| db.add(text1).await?);
            tx!(|db| db.push(root_id, id1).await?);
            tx!(|db| assert_eq!(db.get(id1).await?.unwrap().str()?, "foo"));

            let text2 = Node::text("foobar");
            let id2 = tx!(|db| db.add(text2).await?);
            tx!(|db| db.push(root_id, id2).await?);
            tx!(|db| assert_eq!(db.get(id2).await?.unwrap().str()?, "foobar"));

            let last_updated = tx!(|db| db.last_updated().await?.unwrap());
            let broadcast = tx!(|db| db.publish_broadcast(root_id).await?);

            (id1, id2, broadcast, last_updated)
        };

        assert!(broadcast.expiration.unwrap_or_default() >= last_updated + 60 * 60 * 24);

        let mut current = db.current().await;
        let tile = current.tile(root_id).await?;

        let expected = Tile {
            id: root_id,
            preview: Block::Text {
                styles: BTreeSet::new(),
                spans: vec![
                    Span::Text {
                        styles: BTreeSet::new(),
                        text: "foo".to_string(),
                    }
                ]
            },
            broadcasts: BTreeSet::from_iter(vec![
                Broadcast {
                    broadcast_id: broadcast.broadcast_id.clone(),
                    node_id: root_id,
                    last_updated,
                    expiration: broadcast.expiration,
                }
            ]),
            sections: vec![
                Section {
                    id: None,
                    has_multiple_parents: false,
                    subsections: vec![
                        Subsection {
                            id: id1,
                            block: Block::Text {
                                styles: BTreeSet::new(),
                                spans: vec![
                                    Span::Text {
                                        styles: BTreeSet::new(),
                                        text: "foo".to_string(),
                                    }
                                ]
                            },
                            before: vec![],
                            after: vec![],
                        }
                    ]
                },
                Section {
                    id: None,
                    has_multiple_parents: false,
                    subsections: vec![
                        Subsection {
                            id: id2,
                            block: Block::Text {
                                styles: BTreeSet::new(),
                                spans: vec![
                                    Span::Text {
                                        styles: BTreeSet::new(),
                                        text: "foobar".to_string(),
                                    }
                                ]
                            },
                            before: vec![],
                            after: vec![],
                        }
                    ]
                }
            ],
            branches: vec![],
        };

        assert_eq!(tile, expected);

        let storage = MemoryStorage::new();
        let other = Db::open(storage).await?;

        let mut current = other.current().await;
        let other_tile = current.tile_from_broadcast(&broadcast.broadcast_id).await?;
        let namespaced = current.namespaced_id(&broadcast.broadcast_id.into(), root_id).await?;
        assert_eq!(other_tile.id, namespaced);
        assert_eq!(other_tile.preview, expected.preview);
        assert_eq!(other_tile.broadcasts, BTreeSet::new());
        assert_eq!(other_tile.branches, expected.branches);
        assert_eq!(other_tile.sections.len(), expected.sections.len());
        for (mut found, mut expected) in other_tile.sections.into_iter().zip(expected.sections) {
            assert_eq!(found.id, None);
            assert_eq!(expected.id, None);
            for (found, expected) in found.subsections.iter_mut().zip(expected.subsections.iter_mut()) {
                let found_id = std::mem::replace(&mut found.id, Id::root());
                let expected_id = std::mem::replace(&mut expected.id, Id::root());
                let namespaced = current.namespaced_id(&broadcast.broadcast_id.into(), expected_id).await?;
                assert_eq!(found_id, namespaced);
            }
            assert_eq!(found, expected);
        }
    }
}

test! {
    async fn multi_broadcast_tile(storage) -> Result<()> {
        let db = Db::open(storage).await?;
        let root_id = Id::root();
        let (id2, broadcast1, last_updated1, broadcast2, last_updated2) = {
            let text1 = Node::text("foo");
            let id1 = tx!(|db| db.add(text1).await?);
            tx!(|db| db.push(root_id, id1).await?);

            let text2 = Node::text("foobar");
            let id2 = tx!(|db| db.add(Node::list(Layout::Page, vec![text2])).await?);
            tx!(|db| db.push(root_id, id2).await?);

            let last_updated1 = tx!(|db| db.last_updated().await?.unwrap());
            let broadcast1 = tx!(|db| db.publish_broadcast(root_id).await?);

            let last_updated2 = tx!(|db| db.last_updated().await?.unwrap());
            let broadcast2 = tx!(|db| db.publish_broadcast(id2).await?);

            (id2, broadcast1, last_updated1, broadcast2, last_updated2)
        };

        let mut current = db.current().await;
        let tile = current.tile(root_id).await?;

        assert_eq!(tile.broadcasts, BTreeSet::from_iter(vec![
            Broadcast {
                broadcast_id: broadcast1.broadcast_id.clone(),
                node_id: root_id,
                last_updated: last_updated1,
                expiration: broadcast1.expiration,
            }
        ]));

        let tile = current.tile(id2).await?;

        assert_eq!(tile.broadcasts, BTreeSet::from_iter(vec![
            Broadcast {
                broadcast_id: broadcast2.broadcast_id.clone(),
                node_id: id2,
                last_updated: last_updated2,
                expiration: broadcast2.expiration,
            },
            Broadcast {
                broadcast_id: broadcast1.broadcast_id.clone(),
                node_id: root_id,
                last_updated: last_updated1,
                expiration: broadcast1.expiration,
            }
        ]));

        let storage = MemoryStorage::new();
        let other = Db::open(storage).await?;
        let mut current = other.current().await;
        let broadcast1_id = broadcast1.broadcast_id;
        let broadcast2_id = broadcast2.broadcast_id;

        let other_tile = current.tile_from_broadcast(&broadcast1_id).await?;
        let namespaced_root_id1 = current.namespaced_id(&broadcast1_id, root_id).await?;
        assert_eq!(other_tile.id, namespaced_root_id1);
        assert_eq!(other_tile.broadcasts, BTreeSet::new());

        let other_tile = current.tile_from_broadcast(&broadcast2_id).await?;
        let namespaced_root_id2 = current.namespaced_id(&broadcast2_id, root_id).await?;
        assert_eq!(other_tile.id, namespaced_root_id2);
        assert_eq!(other_tile.broadcasts, BTreeSet::new());
        assert_eq!(other_tile.branches, vec![]);
        assert_eq!(other_tile.sections.len(), 1);
        assert_eq!(other_tile.sections[0].subsections.len(), 1);
        let other_tile_root_sections = other_tile.sections;
        let namespaced = current.namespaced_id(&broadcast2_id, id2).await?;
        let other_tile = current.tile(namespaced).await?;
        assert_eq!(other_tile.id, namespaced);
        assert_eq!(other_tile.broadcasts, BTreeSet::new());
        assert_eq!(other_tile.branches, vec![]);
        assert_eq!(other_tile.sections.len(), 1);
        assert_eq!(other_tile.sections[0].subsections.len(), 1);
        assert_eq!(
            other_tile_root_sections[0].subsections[0],
            other_tile.sections[0].subsections[0]
        );
    }
}