# CLAUDE.md
This file provides guidance to Claude Code when working with the Geode Rust client library.
## Build Commands
```bash
# Build
cargo build # Debug build
cargo build --release # Release build
# Test
cargo test # Run all unit tests (323 tests)
cargo test --lib # Run library tests only
cargo test -- --nocapture # Show println! output
# Lint
cargo clippy # Run clippy lints
cargo fmt # Format code
cargo fmt -- --check # Check formatting
# Benchmarks
cargo bench # Run all benchmarks (59 benchmarks)
cargo bench -- "value" # Run value-related benchmarks
cargo bench -- --test # Test mode (verify benchmarks work)
# Property-based tests (stable Rust)
cargo test --test proptest # Run 28 proptest tests
# Fuzzing (requires nightly Rust)
cargo +nightly fuzz list # List fuzz targets
cargo +nightly fuzz run fuzz_value_from_json # Run a target
# Integration Tests (requires running Geode server)
cargo test --features integration
# Documentation
cargo doc --open # Build and open docs
```
## Running Examples
```bash
# Requires a running Geode server on localhost:3141
cargo run --example basic
cargo run --example advanced
cargo run --example test_quinn
```
## Project Structure
```text
src/
├── lib.rs # Library entry point, re-exports
├── client.rs # Connection, query execution, dual transport support
├── dsn.rs # DSN parsing (quic://, grpc://)
├── grpc.rs # gRPC transport using tonic
├── proto.rs # Protobuf encoding/decoding helpers
├── types.rs # Value types, ValueKind, type conversions
├── query_builder.rs # QueryBuilder, PatternBuilder, PredicateBuilder
├── pool.rs # ConnectionPool for concurrent access
├── error.rs # Error types with is_retryable() support
├── auth.rs # Auth types (User, Role, Permission, RLSPolicy)
└── validate.rs # Input validation (query, params, hostname, port)
```
## Architecture
### Client Module (`client.rs`)
The client module supports dual transports: QUIC (using Quinn) and gRPC (using Tonic):
- **Client**: Builder for configuring connections (host, port, TLS, transport)
- **Connection**: Active connection with query methods (wraps either QUIC or gRPC)
- **ConnectionKind**: Internal enum dispatching to QUIC or gRPC transport
- **Page/Column**: Query result structures
**Connection Flow:**
```text
Client::new() or Client::from_dsn() -> configure -> connect() -> Connection
Connection: query() / query_with_params() / begin() / commit() / rollback()
```
**Protocol:**
- ALPN: `b"geode/1"` (QUIC only)
- Wire format: Protobuf with 4-byte big-endian length prefix (QUIC) or native gRPC framing
- Handshake: HELLO message exchange
- Retry: 3 attempts with 150ms backoff
### DSN Module (`dsn.rs`)
Parses Data Source Name connection strings:
- **Schemes**: `quic://`, `grpc://`, `grpcs://`
- **Transport**: Determines QUIC vs gRPC based on scheme
- **IPv6**: Supports bracket notation for IPv6 addresses
- **Options**: Query parameters for page_size, TLS, auth, etc.
### gRPC Module (`grpc.rs`)
gRPC transport implementation using Tonic:
- **GrpcClient**: Tonic-based client with TLS support
- Stub implementation pending full proto code generation
### Type System (`types.rs`)
25 value kinds supporting all GQL types:
| Scalars | Null, Int, Bool, String, Decimal |
| Collections | Array, Object |
| Binary | Bytea |
| Temporal | Date, Time, TimeTz, Timestamp, TimestampTz, Interval |
| Special | Json, Jsonb, Xml, Url, Domain, Uuid, Enum, BitString, Range |
**Key Functions:**
- `Value::from_json()` / `Value::to_json()` - JSON conversion
- `decode_value(raw, type_name)` - Type-aware decoding from server
- `as_int()`, `as_string()`, etc. - Type-safe accessors
### Query Builders (`query_builder.rs`)
Fluent API for constructing GQL queries:
```rust
let (query, params) = QueryBuilder::new()
.match_pattern("(p:Person)")
.where_clause("p.age > $min_age")
.return_(&["p.name", "p.age"])
.order_by(&["p.age DESC"])
.limit(100)
.with_param("min_age", 25)
.build();
```
**PatternBuilder** for graph patterns:
```rust
let pattern = PatternBuilder::new()
.node("a", "Person")
.edge("r", "KNOWS", EdgeDirection::Outgoing)
.node("b", "Person")
.build();
// "(a:Person)-[r:KNOWS]->(b:Person)"
```
### Error Handling (`error.rs`)
Rich error types with ISO/IEC 39075 support:
| Connection | Yes | Network/QUIC issues |
| Query | Conditional | Query execution (40001/40P01/40502 = retryable) |
| Timeout | Yes | Operation timeout |
| Pool | Yes | Connection pool exhausted |
| Auth | No | Authentication failure |
| Tls | No | TLS/certificate errors |
| InvalidDsn | No | Invalid connection string |
| Type | No | Type conversion errors |
Use `err.is_retryable()` to check if retry is appropriate.
### Connection Pool (`pool.rs`)
Semaphore-based connection pooling:
```rust
let pool = ConnectionPool::new("localhost", 3141, 10)
.skip_verify(true);
let conn = pool.acquire().await?;
let (page, _) = conn.query("RETURN 1").await?;
drop(conn); // Returns to pool
```
## Testing
### Test Organization
Tests are inline in each module using `#[cfg(test)]`:
| error.rs | 48 | Display, From, helpers, is_retryable |
| types.rs | 104 | All value kinds, JSON conversion, decode_value |
| query_builder.rs | 51 | All builders, pattern generation |
| pool.rs | 12 | Configuration, semaphore permits |
| auth.rs | 24 | Serialization, deserialization |
| validate.rs | 25 | Query, param names, hostname, port, page_size |
| dsn.rs | 44 | URL parsing, schemes, IPv6, options |
| grpc.rs | 15 | Proto value conversion, message types |
### Running Specific Tests
```bash
# Run tests for a specific module
cargo test error::tests
cargo test types::tests
cargo test query_builder::tests
cargo test pool::tests
cargo test auth::tests
# Run a specific test
cargo test test_value_int
cargo test test_error_is_retryable
```
## Wire Protocol
### Client Messages
| HELLO | Connection handshake |
| RUN_GQL | Execute GQL query |
| PULL | Fetch result pages |
| BEGIN | Start transaction |
| COMMIT | Commit transaction |
| ROLLBACK | Rollback transaction |
| SAVEPOINT | Create savepoint |
| ROLLBACK_TO | Rollback to savepoint |
| PING | Keep-alive |
### Server Responses
| HELLO | Handshake acknowledgment |
| SCHEMA | Column definitions |
| BINDINGS | Result rows |
| ERROR | Error with ISO code |
| RESULT | Operation success |
| PROFILE | Performance metrics |
## Dependencies
### Core
- `tokio` (1.35) - Async runtime
- `quinn` (0.11) - Pure Rust QUIC transport
- `tonic` (0.12) - gRPC transport with TLS support
- `prost` (0.13) - Protobuf encoding/decoding
- `rustls` (0.23) - TLS 1.3 with AWS-LC-RS crypto
- `url` (2.5) - DSN URL parsing
### Serialization
- `serde` + `serde_json` - JSON handling
- `prost` - Protobuf wire format
### Types
- `rust_decimal` (1.33) - Decimal precision
- `chrono` (0.4) - Temporal types
### Error Handling
- `thiserror` (1.0) - Derive Error trait
## Code Style
- Use `cargo fmt` before committing
- Run `cargo clippy` and address warnings
- Add tests for new functionality
- Document public APIs with rustdoc
## Common Patterns
### Error Handling
```rust
// Use ? operator with Result<T>
let conn = client.connect().await?;
// Check if retry is appropriate
match result {
Err(e) if e.is_retryable() => retry(),
Err(e) => return Err(e),
Ok(v) => v,
}
```
### Parameterized Queries
```rust
use std::collections::HashMap;
let mut params = HashMap::new();
params.insert("name".to_string(), Value::string("Alice").to_json());
params.insert("age".to_string(), Value::int(30).to_json());
let (page, _) = conn.query_with_params(
"CREATE (p:Person {name: $name, age: $age}) RETURN p",
params
).await?;
```
### Transactions
```rust
conn.begin().await?;
conn.query("CREATE (n:Node)").await?;
conn.query("CREATE (m:Node)").await?;
conn.commit().await?;
// Or: conn.rollback().await? on error
```
## Fuzzing & Property Testing
### Property-Based Tests (Stable Rust)
Located in `tests/proptest.rs`, these tests verify invariants with random inputs:
| Value roundtrips | 7 | int, bool, string, decimal, array, object |
| JSON handling | 3 | to_json, from_json, roundtrip |
| Query builders | 6 | QueryBuilder, PatternBuilder, PredicateBuilder |
| Error handling | 2 | Type accessor errors |
| Stress tests | 2 | Large nested structures |
| Fuzz-like | 3 | Random bytes/strings |
Run with: `cargo test --test proptest`
### Fuzz Targets (Nightly Rust)
Located in `fuzz/fuzz_targets/`, these use libFuzzer for deep fuzzing:
| `fuzz_value_from_json` | Value::from_json with arbitrary JSON |
| `fuzz_query_builder` | QueryBuilder with arbitrary strings |
| `fuzz_pattern_builder` | PatternBuilder with arbitrary patterns |
| `fuzz_json_parsing` | JSON parsing and Value conversion |
Run with:
```bash
cargo +nightly fuzz run fuzz_value_from_json
cargo +nightly fuzz run fuzz_value_from_json -- -max_total_time=60
```
## Benchmarks
Benchmarks use Criterion and are located in `benches/benchmarks.rs`:
| value_creation | 12 | Creating Value types |
| value_accessors | 7 | Reading values with type accessors |
| value_clone | 4 | Cloning values of various sizes |
| query_builder | 5 | Building queries with QueryBuilder |
| pattern_builder | 4 | Building graph patterns |
| predicate_builder | 2 | Building WHERE predicates |
| connection | 1 | Connect/disconnect (requires server) |
| query_execution | 4 | Query execution (requires server) |
| query_throughput | 3 | Sequential query throughput |
| decimal_parsing | 6 | Parsing decimal strings |
| json_serialization | 6 | JSON serialize/deserialize |
```bash
# Run all benchmarks
cargo bench
# Run specific group
cargo bench -- "query_builder"
cargo bench -- "connection"
# Save baseline for comparison
cargo bench -- --save-baseline main
# Compare against baseline
cargo bench -- --baseline main
```
## Integration Testing
Integration tests require a running Geode server and are in `tests/integration.rs`:
| Basic operations | 3 | Ping, simple queries, parameterized |
| Node CRUD | 5 | Create, read, update, delete, labels |
| Relationships | 4 | Creation, properties, traversal, direction |
| Transactions | 4 | Begin/commit, rollback, multi-op, savepoints |
| Query operations | 4 | WHERE, ORDER BY, LIMIT/SKIP, predicates |
| Aggregations | 5 | COUNT, SUM, AVG, MIN, MAX |
| Data types | 6 | Null, bool, int, decimal, string, collections |
| Concurrent access | 5 | Connection pool under load |
Run with: `cargo test --features integration`
### Test Harness
Use the test harness for comprehensive cross-client testing:
```bash
cd ../geode-test-harness
make test-rust
```
Or manually:
```bash
# Terminal 1: Start Geode
cd ../geode && ./zig-out/bin/geode serve
# Terminal 2: Run integration examples
cargo run --example basic
```