# Contributing to fraiseql-wire
Thank you for considering contributing to fraiseql-wire! This document provides guidelines and instructions for contributing.
## Code of Conduct
This project is committed to providing a welcoming and inspiring community for all. Please read and respect our community standards.
## Development Setup
### Prerequisites
- Rust 1.75+ (install via [rustup](https://rustup.rs/))
- Postgres 17 (for integration tests)
- Docker (optional, for containerized Postgres)
### Initial Setup
```bash
# Clone the repository
git clone https://github.com/fraiseql/fraiseql-wire.git
cd fraiseql-wire
# Install Rust (if not already installed)
rustup install 1.75
# Verify setup
cargo --version
rustc --version
```
### Docker Setup (Recommended)
For a quick local database without installing Postgres directly:
```bash
# Build Docker image
make docker-build
# Start Postgres container
make docker-up
# Stop container
make docker-down
```
## Running Tests
### Unit Tests
```bash
# Run all unit tests
cargo test --lib
# Run specific module tests
cargo test stream::filter
cargo test client::connection_string
# Run with output
cargo test -- --nocapture
```
### Integration Tests
```bash
# Requires Postgres running (use docker-up or local instance)
# Run all integration tests
cargo test --test integration -- --ignored --nocapture
# Run specific test
cargo test test_streaming_query -- --ignored --nocapture
```
### Full Test Suite
```bash
# Build and run all targets
cargo build --all-targets
cargo test
```
## Code Quality
### Formatting
```bash
# Check formatting
cargo fmt -- --check
# Auto-format code
cargo fmt
```
### Linting
```bash
# Run clippy with all warnings enabled
cargo clippy -- -D warnings
# Stricter mode (includes all clippy warnings)
cargo clippy -- -D warnings -D clippy::all
```
### Type Checking
```bash
# Check without building
cargo check
# Check all examples
cargo check --examples
```
## Documentation
### Building Documentation
```bash
# Build and open documentation
cargo doc --no-deps --open
# Check for doc warnings
cargo rustdoc -- -D missing-docs
# Check specific module
cargo doc --lib fraiseql_wire::client --no-deps --open
```
### Writing Documentation
- All public APIs must have documentation comments
- Use markdown formatting in doc comments
- Include examples for complex APIs
- Document panics, errors, and edge cases
- Keep examples runnable (use no_run for async)
Example:
```rust
/// Execute query and return JSON stream
///
/// # Examples
///
/// ```no_run
/// # async fn example(client: fraiseql_wire::FraiseClient) -> fraiseql_wire::Result<()> {
/// let stream = client.query("user").execute().await?;
/// # Ok(())
/// # }
/// ```
pub async fn execute(self) -> Result<impl Stream<Item = Result<Value>>> {
// ...
}
```
## Making Changes
### Process
1. **Fork** the repository
2. **Create** a feature branch: `git checkout -b feature/my-feature`
3. **Make** your changes with tests
4. **Run** `cargo test` to verify
5. **Commit** with clear messages: `git commit -m "feat: add my feature"`
6. **Push** to your fork: `git push origin feature/my-feature`
7. **Create** a Pull Request with description
### Commit Message Format
Use conventional commits for clear commit history:
```
type(scope): description
[optional body]
[optional footer]
```
Types:
- `feat:` new feature
- `fix:` bug fix
- `refactor:` code refactoring
- `docs:` documentation changes
- `test:` test additions/changes
- `chore:` build, CI, or tooling changes
Example:
```
feat(client): add connection string parsing for Unix sockets
Enables connecting to local Postgres via Unix domain sockets.
Uses whoami for default user when not specified.
Fixes #42
```
### Testing Requirements
All contributions must include tests:
- Unit tests for new functions/modules
- Integration tests for end-to-end behavior
- Edge case tests for error conditions
- No decrease in overall test coverage
```rust
#[test]
fn test_my_feature() {
let result = my_function("input");
assert_eq!(result, "expected");
}
#[tokio::test]
async fn test_my_async_feature() {
let result = my_async_function("input").await;
assert_eq!(result, "expected");
}
```
## Design Principles
fraiseql-wire follows strict design principles. Ensure your contribution aligns with these:
### ✅ Belongs in fraiseql-wire
- Improvements to JSON streaming performance
- Better error messages and error handling
- Enhanced observability (tracing, metrics)
- Documentation and examples
- Bug fixes
- API improvements maintaining backward compatibility
### ❌ Does NOT Belong in fraiseql-wire
- General SQL support beyond constraints
- Write operations (INSERT/UPDATE/DELETE)
- Transaction support
- Connection pooling (separate crate)
- Support for non-JSON types
- Features requiring buffering full result sets
- Authentication methods beyond cleartext
- TLS/encryption (use external service)
## Hard Constraints
These constraints are non-negotiable and relied upon throughout:
- Exactly **one column** in result set
- Column must be named `data`
- Column type must be `json` or `jsonb`
- One active query per connection
- Results streamed **in-order**
- No full result set buffering
- Drop stream to cancel query
- No client-side sorting/aggregation
- Protocol encoding/decoding is pure (no I/O)
- Connection state machine is explicit
## Architecture Overview
### Module Structure
```
src/
├── client/ → Public API (FraiseClient, QueryBuilder)
├── stream/ → Streaming abstractions
├── protocol/ → Postgres wire protocol
├── connection/ → Connection management & state machine
├── json/ → JSON validation
├── util/ → Utilities
├── error.rs → Error types
└── lib.rs → Library root
```
### Data Flow
```
User Code
↓
FraiseClient::connect() → Connection established
↓
client.query() → QueryBuilder
↓
.where_sql() / .where_rust() / .order_by()
↓
.execute() → Postgres query sent
↓
FilteredStream (if Rust predicate)
↓
Stream<Item = Result<Value>>
↓
Consumed by user code
```
## Performance Considerations
- No blocking I/O in async functions
- Minimize allocations in hot paths
- Use references over clones when possible
- Benchmark changes that affect streaming
- Memory should scale with chunk_size, not result size
## CI/CD Workflows
This project uses GitHub Actions for automated testing and releases.
### Continuous Integration
Every push to `main` and pull request triggers:
- **Build & Test**: Compiles with Rust stable, runs unit tests
- **Code Coverage**: Generates coverage report (target: >85%)
- **MSRV**: Tests with Rust 1.70 for backward compatibility
- **Integration Tests**: Runs against Postgres 15 service
- **Documentation**: Checks for doc warnings
- **Security Audit**: Runs `cargo audit` to detect vulnerabilities
See [CI_CD_GUIDE.md](CI_CD_GUIDE.md) for detailed workflow documentation.
### Release Process
The maintainers follow this automated process for releases:
1. Update version in Cargo.toml and CHANGELOG.md
2. Run full test suite locally
3. Execute release script: `./scripts/publish.sh 0.1.0`
4. Script automatically:
- Validates semver format
- Verifies clean git state
- Builds and tests release
- Creates git tag and pushes
- Publishes to crates.io
5. GitHub Actions creates release on crates.io
For detailed release instructions, see [CI_CD_GUIDE.md](CI_CD_GUIDE.md#making-a-release).
Contributors don't need to handle releases.
## Getting Help
- **Questions?** Open a [GitHub Discussion](https://github.com/fraiseql/fraiseql-wire/discussions)
- **Found a bug?** Open a [GitHub Issue](https://github.com/fraiseql/fraiseql-wire/issues)
- **Want to discuss design?** Open an issue before starting major work
## Resources
- [Rust Book](https://doc.rust-lang.org/book/)
- [Tokio Tutorial](https://tokio.rs/tokio/tutorial)
- [Postgres Protocol Docs](https://www.postgresql.org/docs/17/protocol.html)
- [Futures Crate Docs](https://docs.rs/futures/)
- [FraiseQL Architecture Docs](.claude/CLAUDE.md)
## License
By contributing to fraiseql-wire, you agree that your contributions will be licensed under the same license terms (MIT OR Apache-2.0).
Thank you for contributing to fraiseql-wire! 🎉