Code Style
QilbeeDB follows standard Rust conventions and best practices.
Rust Style Guide#
Formatting#
Use rustfmt for consistent formatting:
# Format all code
cargo fmt
# Check formatting
cargo fmt -- --check
Configuration in rustfmt.toml:
max_width = 100
tab_spaces = 4
edition = "2021"
Naming Conventions#
-
Types:
PascalCaserust struct NodeId(u64); enum PropertyValue { ... } -
Functions:
snake_caserust fn create_node(labels: Vec<String>) -> Result<Node> -
Constants:
SCREAMING_SNAKE_CASErust const MAX_BATCH_SIZE: usize = 1000; -
Modules:
snake_caserust mod query_engine; mod storage_backend;
Error Handling#
Use Result for fallible operations:
// Good
pub fn get_node(&self, id: NodeId) -> Result<Node> {
self.storage
.get(id)
.ok_or(Error::NodeNotFound(id))
}
// Bad: unwrap/expect in library code
pub fn get_node(&self, id: NodeId) -> Node {
self.storage.get(id).unwrap() // Don't do this!
}
Documentation#
Document public APIs with doc comments:
/// Creates a new node with the specified labels and properties.
///
/// # Arguments
///
/// * `labels` - A vector of label strings
/// * `properties` - A hashmap of property key-value pairs
///
/// # Examples
///
/// ```
/// let node = graph.create_node(
/// vec!["User".to_string()],
/// hashmap!{"name" => "Alice".into()}
/// )?;
/// ```
///
/// # Errors
///
/// Returns `Error::InvalidLabel` if labels are empty.
pub fn create_node(
&mut self,
labels: Vec<String>,
properties: HashMap<String, PropertyValue>
) -> Result<Node> {
// ...
}
Code Organization#
Module Structure#
// src/lib.rs
pub mod graph;
pub mod storage;
pub mod query;
pub mod memory;
// src/graph/mod.rs
mod node;
mod relationship;
pub use node::Node;
pub use relationship::Relationship;
Imports#
Group imports by category:
// Standard library
use std::collections::HashMap;
use std::sync::Arc;
// External crates
use serde::{Deserialize, Serialize};
use tokio::sync::RwLock;
// Internal modules
use crate::storage::Storage;
use crate::error::{Error, Result};
Testing#
Unit Tests#
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_node() {
let mut graph = Graph::new();
let node = graph.create_node(
vec!["User".to_string()],
HashMap::new()
).unwrap();
assert_eq!(node.labels, vec!["User"]);
}
}
Integration Tests#
Place in tests/ directory:
// tests/graph_operations.rs
use qilbeedb::Graph;
#[test]
fn test_create_and_query_nodes() {
let mut graph = Graph::new();
// ...
}
Linting#
Run Clippy for lint checks:
# Run Clippy
cargo clippy
# Fix warnings
cargo clippy --fix
Common Clippy lints:
- Prefer if let over match for single patterns
- Use into() instead of explicit conversions
- Avoid unnecessary clones
Performance#
Avoid Unnecessary Allocations#
// Good: Use references
fn process_nodes(&self, nodes: &[Node]) { ... }
// Bad: Unnecessary clone
fn process_nodes(&self, nodes: Vec<Node>) { ... }
Use Appropriate Data Structures#
// Good: HashMap for lookups
let mut index: HashMap<NodeId, Node> = HashMap::new();
// Bad: Vec for frequent lookups
let mut index: Vec<(NodeId, Node)> = Vec::new();
Git Commit Messages#
Follow conventional commits:
feat: Add support for variable-length paths
fix: Correct index selection in query planner
docs: Update API documentation for graph operations
test: Add integration tests for memory consolidation
refactor: Simplify relationship storage logic
perf: Optimize node scan with bloom filters
Format:
<type>(<scope>): <subject>
<body>
<footer>
Pull Request Guidelines#
- Create feature branch from
main - Write tests for new functionality
- Update documentation
- Run full test suite
- Format code with
rustfmt - Run
clippyand fix warnings - Write clear PR description
Next Steps#
- Set up Development Environment
- Write Tests
- Read Architecture