gwp 0.1.0

A standalone, pure Rust gRPC wire protocol for GQL (ISO/IEC 39075)
Documentation

GWP

A standalone, pure Rust gRPC wire protocol for GQL (ISO/IEC 39075) - the international standard query language for property graphs.

Any GQL-compatible database engine can plug in via the GqlBackend trait. GWP handles gRPC transport, session management, transactions, and the full GQL type system over the wire.

Features

  • Spec-faithful - Full GQL type system, GQLSTATUS codes, session/transaction semantics
  • Pure Rust - No C/C++ dependencies, #![forbid(unsafe_code)]
  • Lightweight - Minimal deps: tonic, prost, tokio
  • Fast - Streaming results via server-side gRPC streaming
  • Embeddable - Library-first design, usable by any Rust project

Quick Start

Add to your Cargo.toml:

[dependencies]
gwp = "0.1"

Implementing a Backend

Implement the GqlBackend trait to connect your database:

use gwp::server::{GqlBackend, SessionHandle, TransactionHandle, SessionConfig};
use gwp::error::GqlError;

struct MyDatabase { /* ... */ }

#[tonic::async_trait]
impl GqlBackend for MyDatabase {
    async fn create_session(&self, config: &SessionConfig) -> Result<SessionHandle, GqlError> {
        // Create a session in your database
        Ok(SessionHandle("session-1".to_owned()))
    }

    async fn execute(
        &self,
        session: &SessionHandle,
        statement: &str,
        parameters: &std::collections::HashMap<String, gwp::types::Value>,
        transaction: Option<&TransactionHandle>,
    ) -> Result<std::pin::Pin<Box<dyn gwp::server::ResultStream>>, GqlError> {
        // Execute GQL and return a result stream
        todo!()
    }

    // ... other trait methods
}

Starting the Server

use gwp::server::GqlServer;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let backend = MyDatabase::new();
    let addr = "127.0.0.1:50051".parse()?;

    println!("GQL server listening on {addr}");
    GqlServer::serve(backend, addr).await?;

    Ok(())
}

Using the Client

use gwp::client::GqlConnection;
use std::collections::HashMap;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut conn = GqlConnection::connect("http://127.0.0.1:50051").await?;
    let mut session = conn.create_session().await?;

    let mut cursor = session.execute("MATCH (n:Person) RETURN n.name", HashMap::new()).await?;

    while let Some(row) = cursor.next_row().await? {
        println!("{row:?}");
    }

    session.close().await?;
    Ok(())
}

Architecture

Application (GQL statements, parameters, results)
       |
       v
  gRPC Services
  - SessionService: handshake, configure, reset, close, ping
  - GqlService:     execute, begin_transaction, commit, rollback
       |
       v
  Protocol Buffers (prost)
  - Full GQL type system: Value, Node, Edge, Path, Record
  - GQLSTATUS codes for structured error reporting
       |
       v
  GqlBackend trait (your database plugs in here)

GQL Type Support

GQL Type Wire Representation
NULL, BOOLEAN, INTEGER, FLOAT, STRING, BYTES Native protobuf types
DATE, TIME, DATETIME, DURATION Custom messages
LIST, MAP Recursive Value containers
NODE ID + labels + properties
EDGE ID + type + endpoints + properties
PATH Alternating nodes and edges
BIGINTEGER, BIGFLOAT, DECIMAL String-encoded precision types

Modules

Module Description
proto Generated protobuf types and gRPC stubs
types Ergonomic Rust wrappers over proto types
server GqlBackend trait, session/transaction management, gRPC server
client GqlConnection, GqlSession, ResultCursor, Transaction
error GqlError enum
status GQLSTATUS code constants and helpers

Requirements

  • Rust 1.85.0+ (edition 2024)
  • protoc (Protocol Buffers compiler) - required at build time

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.