graph_d 1.3.2

A native graph database implementation in Rust with built-in JSON support and SQLite-like simplicity
Documentation
//! Example demonstrating persistent storage using memory-mapped files.

use graph_d::{Graph, Result};
use serde_json::json;
use std::collections::HashMap;

fn main() -> Result<()> {
    println!("=== Persistent Storage Demo ===\n");

    let db_path = "example_graph.db";

    // Create a new persistent graph database
    println!("Creating new persistent graph at: {db_path}");
    let mut graph = Graph::open(db_path)?;

    // Create some sample data
    println!("Adding nodes and relationships...");

    let alice_id = graph.create_node(
        [
            ("name".to_string(), json!("Alice")),
            ("role".to_string(), json!("Engineer")),
            ("level".to_string(), json!("Senior")),
        ]
        .into(),
    )?;

    let bob_id = graph.create_node(
        [
            ("name".to_string(), json!("Bob")),
            ("role".to_string(), json!("Manager")),
            ("team".to_string(), json!("Platform")),
        ]
        .into(),
    )?;

    let charlie_id = graph.create_node(
        [
            ("name".to_string(), json!("Charlie")),
            ("role".to_string(), json!("Designer")),
            ("specialty".to_string(), json!("UX")),
        ]
        .into(),
    )?;

    // Create relationships
    let _rel1 = graph.create_relationship(
        alice_id,
        bob_id,
        "REPORTS_TO".to_string(),
        [("since".to_string(), json!("2023-01-01"))].into(),
    )?;

    let _rel2 = graph.create_relationship(
        alice_id,
        charlie_id,
        "COLLABORATES_WITH".to_string(),
        [
            ("project".to_string(), json!("Dashboard Redesign")),
            ("frequency".to_string(), json!("weekly")),
        ]
        .into(),
    )?;

    let _rel3 =
        graph.create_relationship(bob_id, charlie_id, "MANAGES".to_string(), HashMap::new())?;

    println!(
        "Created {} nodes and {} relationships",
        graph.storage.node_count(),
        graph.storage.relationship_count()
    );

    // Demonstrate querying
    println!("\n=== Querying the Graph ===");

    if let Some(alice) = graph.get_node(alice_id)? {
        println!("Alice's profile: {:?}", alice.properties);

        let relationships = graph.get_relationships_for_node(alice_id)?;
        println!("Alice's relationships:");
        for rel in relationships {
            let other_node_id = if rel.from_id == alice_id {
                rel.to_id
            } else {
                rel.from_id
            };
            if let Some(other_node) = graph.get_node(other_node_id)? {
                let other_name = other_node
                    .get_property("name")
                    .and_then(|v| v.as_str())
                    .unwrap_or("Unknown");
                println!(
                    "  - {} {} {}",
                    rel.rel_type,
                    if rel.from_id == alice_id {
                        "to"
                    } else {
                        "from"
                    },
                    other_name
                );
            }
        }
    }

    // Flush data to disk
    println!("\n=== Persisting to Disk ===");
    graph.storage.flush()?;
    println!("Data flushed to disk: {db_path}");

    println!("\nReopening database to verify persistence...");
    let graph2 = Graph::open(db_path)?;
    println!(
        "Reopened graph with {} nodes and {} relationships",
        graph2.storage.node_count(),
        graph2.storage.relationship_count()
    );

    // Note: Current implementation only persists metadata (counts) in the header
    // Full data persistence would require implementing record serialization

    println!("\n=== Memory-Mapped Storage Benefits ===");
    println!("✓ File-based persistence foundation");
    println!("✓ Memory-efficient access patterns");
    println!("✓ Support for large datasets");
    println!("✓ ACID transaction framework");
    println!("✓ Concurrent access support (via locking)");

    println!("\nDemo completed successfully!");

    // Clean up
    std::fs::remove_file(db_path).ok();

    Ok(())
}