# Contributing to OCG (OpenCypher Graph)
Thank you for your interest in contributing to OCG! 🎉
This document provides guidelines for contributing to the project.
## Table of Contents
- [Development Setup](#development-setup)
- [Running Tests](#running-tests)
- [Code Style](#code-style)
- [Pull Request Process](#pull-request-process)
- [Reporting Bugs](#reporting-bugs)
- [Suggesting Features](#suggesting-features)
- [Project Structure](#project-structure)
- [Release Process](#release-process)
## Development Setup
### Prerequisites
- **Rust** 1.70+ (install via [rustup](https://rustup.rs/))
```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup update stable
```
- **Python** 3.8+ (for Python bindings)
```bash
brew install python@3.11
sudo apt install python3.11 python3.11-dev
```
- **Git**
```bash
brew install git
sudo apt install git
```
### Clone and Build
```bash
# Clone repository
git clone https://github.ibm.com/enjoycode/nxcypher-networkit.git
cd nxcypher-networkit
# Build all features
cargo build --all-features
# Run tests
cargo test --all-features
# Build release version
cargo build --release --all-features
```
### Python Development
For working on Python bindings:
```bash
# Install maturin (build tool for PyO3)
pip install maturin
# Build and install locally (development mode)
maturin develop --features python
# Test Python import
python3 -c "import ocg; print(ocg.__version__)"
# Build wheel
maturin build --release --features python --out dist/
# Install wheel
pip install dist/*.whl
```
### IDE Setup
#### VS Code
Recommended extensions:
- `rust-lang.rust-analyzer` - Rust language support
- `tamasfe.even-better-toml` - TOML file support
- `ms-python.python` - Python support
Recommended settings (`.vscode/settings.json`):
```json
{
"rust-analyzer.checkOnSave.command": "clippy",
"rust-analyzer.cargo.features": "all",
"editor.formatOnSave": true,
"[rust]": {
"editor.defaultFormatter": "rust-lang.rust-analyzer"
}
}
```
#### IntelliJ IDEA / CLion
- Install "Rust" plugin
- Install "Python" plugin
- Enable "Reformat on save"
## Running Tests
### Rust Tests
```bash
# All tests
cargo test --all-features
# Unit tests only
cargo test --lib
# Integration tests
cargo test --test '*'
# Specific test file
cargo test --test tck_property_graph
# Specific test
cargo test test_create_node
# With output
cargo test -- --nocapture
# Without Python features (faster)
cargo test --no-default-features
```
### openCypher TCK Tests
```bash
# Run full TCK suite (3,874 scenarios)
cargo test --test tck_property_graph
# Run with verbose output
cargo test --test tck_property_graph -- --nocapture
# Expected: 3,851/3,874 pass (99.0%)
```
### Python TCK Tests
```bash
# Install behave
pip install behave
# Run all Python TCK tests
cd tests/tck
python3 -m behave features/
# Run specific feature
python3 -m behave features/expressions/boolean/Boolean1.feature
# With verbose output
python3 -m behave features/ --verbose
```
### Benchmark Tests
```bash
# Run all benchmarks
cargo bench
# Specific benchmark
cargo bench --bench comparison
# Save baseline
cargo bench -- --save-baseline main
# Compare with baseline
cargo bench -- --baseline main
```
## Code Style
### Rust
**Formatting**: Use `rustfmt`
```bash
# Format all code
cargo fmt
# Check formatting without modifying
cargo fmt --check
```
**Linting**: Use `clippy`
```bash
# Run clippy
cargo clippy --all-features
# Fail on warnings
cargo clippy --all-features -- -D warnings
# Fix automatically (when possible)
cargo clippy --fix --all-features
```
**Documentation**: Add rustdoc comments to all public items
```rust
/// Creates a new node in the graph.
///
/// # Arguments
///
/// * `labels` - Vector of label strings
/// * `properties` - Map of property names to values
///
/// # Returns
///
/// The unique ID of the created node.
///
/// # Examples
///
/// ```
/// use ocg::PropertyGraph;
/// let mut graph = PropertyGraph::new();
/// let node_id = graph.create_node(vec!["Person".to_string()], HashMap::new());
/// ```
pub fn create_node(&mut self, labels: Vec<String>, properties: HashMap<String, CypherValue>) -> u64 {
// implementation
}
```
**Error Handling**: Prefer `Result<T, E>` over `unwrap()`
```rust
// ❌ Avoid
let value = map.get(&key).unwrap();
// ✅ Prefer
let value = map.get(&key)
.ok_or(ExecutionError::KeyNotFound(key.to_string()))?;
// Or with context
let value = map.get(&key)
.ok_or_else(|| ExecutionError::NodeNotFound(id))?;
```
**Naming Conventions**:
- Types: `PascalCase`
- Functions/variables: `snake_case`
- Constants: `SCREAMING_SNAKE_CASE`
- Modules: `snake_case`
### Python
**Style**: Follow PEP 8
```bash
# Install formatters
pip install black isort
# Format code
black python/
isort python/
```
**Type Hints**: Add type annotations
```python
from typing import Dict, List, Optional
def execute(query: str, params: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
"""Execute an openCypher query."""
pass
```
**Docstrings**: Use Google-style docstrings
```python
def execute(query: str, params: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
"""Execute an openCypher query.
Args:
query: The openCypher query string
params: Optional query parameters
Returns:
List of result rows as dictionaries
Raises:
SyntaxError: If query has syntax errors
ExecutionError: If query fails during execution
Examples:
>>> graph = Graph()
>>> result = graph.execute("MATCH (n) RETURN n")
>>> print(len(result))
0
"""
pass
```
## Pull Request Process
### 1. Fork and Branch
```bash
# Fork the repository on GitHub
# Then clone your fork
git clone https://github.com/YOUR_USERNAME/ocg.git
cd ocg
# Add upstream remote
git remote add upstream https://github.ibm.com/enjoycode/nxcypher-networkit.git
# Create feature branch
git checkout -b feature/amazing-feature
```
### 2. Make Changes
- Write code following style guidelines
- Add tests for new functionality
- Update documentation
- Ensure all tests pass
### 3. Commit Changes
Follow [Conventional Commits](https://www.conventionalcommits.org/):
```bash
# Format: <type>(<scope>): <description>
git commit -m "feat(parser): add support for UNION queries"
git commit -m "fix(executor): handle null values in aggregations"
git commit -m "docs(readme): update installation instructions"
git commit -m "test(tck): add tests for temporal functions"
git commit -m "refactor(backend): simplify node creation"
```
**Types**:
- `feat`: New feature
- `fix`: Bug fix
- `docs`: Documentation changes
- `test`: Test changes
- `refactor`: Code refactoring
- `perf`: Performance improvements
- `chore`: Maintenance tasks
### 4. Pre-PR Checklist
Before opening a PR, ensure:
- [ ] **Code compiles**: `cargo build --all-features`
- [ ] **All tests pass**: `cargo test --all-features`
- [ ] **No clippy warnings**: `cargo clippy --all-features -- -D warnings`
- [ ] **Code formatted**: `cargo fmt --check`
- [ ] **Documentation updated** (if needed)
- [ ] **CHANGELOG.md updated** (for non-trivial changes)
- [ ] **TCK compliance maintained**: 99.0%+ (3,851+ scenarios)
- [ ] **Commit messages follow convention**
```bash
# Run all checks
cargo fmt --check && \
cargo clippy --all-features -- -D warnings && \
cargo test --all-features && \
cargo test --test tck_property_graph
```
### 5. Push and Open PR
```bash
# Push to your fork
git push origin feature/amazing-feature
# Open PR on GitHub
# Fill in the PR template
```
### 6. PR Review
- Address reviewer feedback
- Keep PR focused (one feature/fix per PR)
- Squash commits if requested
- Be patient and respectful
### 7. Merge
- Maintainer will merge after approval
- Delete your feature branch after merge
## Reporting Bugs
### Before Reporting
1. **Check existing issues**: Search for similar bugs
2. **Update to latest**: Ensure bug exists in latest version
3. **Minimal reproduction**: Create smallest example that reproduces issue
### Bug Report Template
Open an issue with:
**Title**: Short, descriptive title
**Environment**:
- OS: Ubuntu 22.04
- Rust version: 1.70.0
- Python version: 3.11.5 (if relevant)
- OCG version: 0.1.0
**Description**: Clear description of the bug
**To Reproduce**:
```python
from ocg import Graph
graph = Graph()
# Minimal code that reproduces the bug
```
**Expected behavior**: What should happen
**Actual behavior**: What actually happens
**Error message** (if any):
```
Error: ...
```
**Additional context**: Any other relevant information
## Suggesting Features
### Before Suggesting
1. **Check existing issues**: Feature may already be requested
2. **Check openCypher spec**: Ensure feature aligns with specification
3. **Consider alternatives**: Think about different approaches
### Feature Request Template
Open an issue with:
**Title**: Short feature description
**Problem**: What problem does this solve?
**Proposed Solution**: How should it work?
**openCypher Compatibility**: Does this relate to openCypher spec?
- If yes, provide reference: https://opencypher.org/...
**Examples**:
```cypher
-- Example query
CREATE INDEX ON :Person(name)
```
**Alternatives Considered**: Other approaches you considered
**Additional Context**: Any other relevant information
## Project Structure
```
nxcypher-networkit/
├── src/
│ ├── lib.rs # Library entry point
│ ├── python.rs # PyO3 Python bindings
│ ├── parser/ # openCypher parser
│ │ ├── mod.rs
│ │ ├── lexer.rs
│ │ └── grammar.rs
│ ├── ast/ # Abstract syntax tree
│ │ └── builder.rs
│ ├── executor/ # Query executor
│ │ ├── mod.rs
│ │ ├── evaluator.rs
│ │ ├── pattern_matcher.rs
│ │ └── functions/
│ ├── graph/ # Graph backends
│ │ ├── mod.rs
│ │ ├── backend.rs
│ │ └── backends/
│ │ ├── property_graph.rs
│ │ ├── networkit_rust/
│ │ ├── rustworkx_core/
│ │ └── graphrs/
│ ├── result/ # Result types
│ │ └── value.rs
│ └── errors.rs # Error types
├── tests/
│ ├── tck_property_graph.rs # openCypher TCK tests
│ ├── tck_networkit.rs
│ └── tck/ # Python TCK (behave)
│ ├── features/
│ ├── steps/
│ └── environment.py
├── python/
│ └── ocg/
│ └── __init__.py # Python package
├── benches/ # Benchmarks
│ └── comparison.rs
├── Cargo.toml # Rust dependencies
├── pyproject.toml # Python package config
└── README.md
```
## Release Process
### Version Numbers
Follow [Semantic Versioning](https://semver.org/):
- **MAJOR**: Incompatible API changes (1.0.0 → 2.0.0)
- **MINOR**: New features, backwards-compatible (0.1.0 → 0.2.0)
- **PATCH**: Bug fixes, backwards-compatible (0.1.0 → 0.1.1)
### Creating a Release
1. **Update version** in `Cargo.toml`
2. **Update CHANGELOG.md** with changes
3. **Run full test suite**:
```bash
cargo test --all-features
cargo test --test tck_property_graph
```
4. **Commit changes**:
```bash
git add Cargo.toml CHANGELOG.md
git commit -m "chore: release v0.2.0"
git push
```
5. **Create and push tag**:
```bash
git tag v0.2.0
git push origin v0.2.0
```
6. **GitHub Actions** will automatically:
- Build 65+ wheels
- Run tests on all platforms
- Publish to PyPI
- Create GitHub Release
## Communication
### Getting Help
- **Questions**: Open an issue with `question` label
- **Discussions**: Use GitHub Discussions
- **Security**: See [SECURITY.md](SECURITY.md)
### Code of Conduct
This project follows the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md).
Please be:
- **Respectful** of differing viewpoints
- **Constructive** in feedback
- **Patient** with maintainers and contributors
- **Professional** in all interactions
## License
By contributing, you agree that your contributions will be licensed under the [Apache License 2.0](LICENSE).
All contributions must:
- Be your original work
- Not violate any copyrights or licenses
- Be compatible with Apache 2.0 license
## Recognition
Contributors will be:
- Listed in release notes
- Credited in CHANGELOG.md (for significant contributions)
- Acknowledged in documentation (for major features)
Thank you for contributing to OCG! 🚀