Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Defining a Model

Overview

Graph API provides a flexible way to define your graph data model using Rust's enum types and derive macros. This approach gives you the benefits of Rust's type system while maintaining the flexibility of property graphs.

Basic Concepts

A graph consists of two primary elements:

  1. Vertices (nodes): The entities in your graph
  2. Edges: The relationships connecting vertices

For each of these, you'll define a Rust enum that represents all possible types.

Model Definition

Diagram showing graph elements (Person, Project vertices) and relationships (Follows, Created edges)

The equivalent definition using Graph API is:

// Define vertex types for a social media application
#[derive(Debug, Clone, VertexExt)]
pub enum Vertex {
    // Person vertex with various properties
    Person {
        name: String, // Not indexed

        #[index(hash)] // Hash index for exact lookups
        username: String,

        #[index(full_text)] // Full-text index for text search
        biography: String,

        #[index(range)] // Range index for range queries
        age: u8,
    },

    // Project vertex with minimal properties
    Project {
        name: String,
    },

    // Comment vertex
    Comment {
        text: String,
        date: String,
    },
}

// Define edge types that connect vertices
#[derive(Debug, Clone, EdgeExt)]
pub enum Edge {
    // Simple edges without properties
    Created,
    Follows,

    // Edges with properties
    Liked { timestamp: String },
    Commented { timestamp: String },
}

This model defines vertex types for people, projects, and comments, along with edge types for the relationships between them.

Creating Instances

Once you've defined your model, you can create instances of vertices and edges:

Diagram showing the specific graph instance created by the code
    let mut graph = SimpleGraph::new();

    // Create vertices
    let bryn = graph.add_vertex(Vertex::Person {
        name: "Bryn".to_string(),
        username: "bryn123".to_string(),
        biography: "Graph enthusiast".to_string(),
        age: 28,
    });

    let julia = graph.add_vertex(Vertex::Person {
        name: "Julia".to_string(),
        username: "julia456".to_string(),
        biography: "Software developer".to_string(),
        age: 34,
    });

    let eve = graph.add_vertex(Vertex::Person {
        name: "Eve".to_string(),
        username: "eve789".to_string(),
        biography: "Network specialist".to_string(),
        age: 31,
    });

    let graph_api = graph.add_vertex(Vertex::Project {
        name: "GraphApi".to_string(),
    });

    let alpaca = graph.add_vertex(Vertex::Project {
        name: "Alpaca".to_string(),
    });

    // Create edges
    graph.add_edge(bryn, graph_api, Edge::Created);
    graph.add_edge(julia, alpaca, Edge::Created);
    graph.add_edge(julia, bryn, Edge::Follows);
    graph.add_edge(eve, julia, Edge::Follows);
    graph.add_edge(bryn, eve, Edge::Follows);
    graph.add_edge(
        bryn,
        alpaca,
        Edge::Liked {
            timestamp: "2023-01-01".to_string(),
        },
    );
    graph.add_edge(
        bryn,
        alpaca,
        Edge::Commented {
            timestamp: "2023-01-02".to_string(),
        },
    );

Using Derive Macros

The VertexExt and EdgeExt derive macros generate implementations for your model types that enable them to work with Graph API's traversal and query features.

VertexExt

This macro provides:

  • Integration with the indexing system
  • Projection types
  • Type-safe accessors for properties
  • Type-safe filters for traversals

EdgeExt

This macro provides:

  • Integration with label-based indexing
  • Projection types
  • Type-safe accessors for properties
  • Type-safe filters for traversals

Indexing

You can define indexes for efficient lookups using attributes:

  • #[index(hash)]: Creates a hash index for exact match lookups
  • #[index(range)]: Creates a range index for range queries
  • #[index(full_text)]: Creates a full-text index for text search

For more details on indexes and examples, see the Property Graphs section.

Best Practices

When defining your graph model:

  1. Use descriptive names - Choose clear names for vertex and edge types
  2. Index strategically - Only index fields used in frequent queries
  3. Use appropriate index types - Match index types to query patterns