selene-db-graph 1.3.0

In-memory property-graph storage core (ArcSwap + imbl CoW, label/typed indexes, write funnel) for selene-db.
Documentation
use std::fs;

use selene_core::{
    Change, EdgeTypeDefV1, GraphId, GraphTypeId, LabelSet, NodeTypeDefV1, NodeTypeRef,
    PredefinedValueType, PropertyDefV1, SchemaChange, ValueType, ValueTypeCardinality, db_string,
};
use smallvec::smallvec;

use crate::{EdgeEndpointDef, SharedGraph, ValidationMode};

use super::super::{append_wal, empty_closed_graph_type, temp_dir};

fn legacy_string_property(name: &str, required: bool) -> PropertyDefV1 {
    PropertyDefV1 {
        name: db_string(name).unwrap(),
        value_type: ValueType {
            predefined: Some(PredefinedValueType::String),
            decimal_type: None,
            character_string_type: None,
            byte_string_type: None,
            union: None,
            list_of: None,
            record: None,
            not_null: required,
            cardinality: ValueTypeCardinality::ExactlyOne,
        },
        nullable: !required,
        default: None,
    }
}

#[test]
fn recover_closed_wal_only_decodes_legacy_catalog_ddl_v1() {
    let dir = temp_dir("closed-schema-legacy-wal-only");
    let graph_id = GraphId::new(20);
    let base = empty_closed_graph_type();
    let graph_type = GraphTypeId::new(1).unwrap();
    let sensor = db_string("LegacySensor").unwrap();
    let linked = db_string("LEGACY_LINKED").unwrap();
    let changes = vec![
        Change::SchemaChanged {
            graph: graph_id,
            change: SchemaChange::NodeTypeAdded {
                graph_type,
                label: sensor.clone(),
                def: NodeTypeDefV1 {
                    labels: LabelSet::single(sensor.clone()),
                    properties: smallvec![legacy_string_property("serial", true)],
                    key: None,
                },
            },
        },
        Change::SchemaChanged {
            graph: graph_id,
            change: SchemaChange::EdgeTypeAdded {
                graph_type,
                label: linked.clone(),
                def: EdgeTypeDefV1 {
                    label: linked.clone(),
                    source_node_type: NodeTypeRef(sensor.clone()),
                    target_node_type: NodeTypeRef(sensor.clone()),
                    properties: smallvec![legacy_string_property("since", false)],
                },
            },
        },
    ];
    append_wal(&dir, 0, &changes);

    let recovered = SharedGraph::recover_closed(&dir, graph_id, base).unwrap();
    let graph_type = recovered.graph_type().unwrap();
    let node_type = &graph_type.node_types[0];
    assert_eq!(node_type.name, sensor);
    assert_eq!(node_type.validation_mode, ValidationMode::Strict);
    assert_eq!(node_type.properties[0].name.as_str(), "serial");
    assert!(node_type.properties[0].required);
    assert!(!node_type.properties[0].immutable);
    let edge_type = &graph_type.edge_types[0];
    assert_eq!(edge_type.name, linked);
    assert_eq!(edge_type.source_node_type, EdgeEndpointDef::NodeType(0));
    assert_eq!(edge_type.target_node_type, EdgeEndpointDef::NodeType(0));
    assert_eq!(edge_type.validation_mode, ValidationMode::Strict);
    assert_eq!(edge_type.properties[0].name.as_str(), "since");
    assert!(!edge_type.properties[0].required);
    assert!(!edge_type.properties[0].immutable);
    let _ = fs::remove_dir_all(dir);
}