Contributing to Relica

March 5, 2026 ยท View on GitHub

Thank you for your interest in contributing to Relica! We appreciate your help in making this database query builder better.


๐Ÿš€ Quick Start

Prerequisites

Setup Development Environment

# Fork the repository on GitHub first!

# Clone your fork
git clone https://github.com/YOUR_USERNAME/relica.git
cd relica

# Add upstream remote
git remote add upstream https://github.com/coregx/relica.git

# Install dependencies
go mod download
go mod verify

# Run tests to verify setup
go test ./...

๐Ÿ› ๏ธ Development Workflow

Running Tests

# Run all tests
go test ./...

# Run with coverage
go test -cover ./...

# Run with verbose output
go test -v ./...

# Run specific package tests
go test ./core/...
go test ./cache/...

# Run integration tests (requires databases)
cd test
go test -v ./...

Code Quality

# Format code
gofmt -w .

# Check formatting
gofmt -l .

# Run static analysis
go vet ./...

# Run linter
golangci-lint run --timeout=5m ./...

# Fix auto-fixable issues
golangci-lint run --fix ./...

Benchmarks

# Run all benchmarks
go test -bench=. -benchmem ./benchmark/...

# Run specific benchmark
go test -bench=BenchmarkBatchInsert ./benchmark/...

# Compare benchmarks
go test -bench=. -benchmem ./benchmark/... > new.txt
# Make changes...
go test -bench=. -benchmem ./benchmark/... > old.txt
benchstat old.txt new.txt

๐Ÿ“‹ Before You Submit

Pre-Commit Checklist

Before submitting a pull request, ensure:

  • Code is formatted: gofmt -w .
  • Tests pass: go test ./...
  • Linter passes: golangci-lint run ./...
  • Coverage maintained or improved
  • Documentation updated (if needed)
  • Examples updated (if API changed)
  • CHANGELOG.md updated (for significant changes)

Writing Tests

All new code must include tests:

func TestNewFeature(t *testing.T) {
    // Arrange
    db := setupTestDB(t)
    defer db.Close()

    // Act
    result, err := db./* your code */

    // Assert
    require.NoError(t, err)
    assert.Equal(t, expected, result)
}

Coverage requirements:

  • Minimum: 70% overall coverage
  • Target: 80%+ for business logic
  • Core package: 80%+ required

Code Style

Follow these guidelines:

  1. Naming:

    • Use PascalCase for exported functions/types
    • Use camelCase for unexported functions/types
    • Use descriptive names (avoid abbreviations)
  2. Comments:

    • All exported functions must have godoc comments
    • Comments must start with the function/type name
    • Comments must end with a period
    • Use full sentences
  3. Error Handling:

    • Always handle errors explicitly
    • Use fmt.Errorf with %w for error wrapping
    • Return errors, don't panic (except in tests)
  4. Imports:

    • Group imports: stdlib, external, internal
    • Use goimports for automatic formatting

Example:

// BatchInsert creates a batch INSERT query for multiple rows.
// It returns a BatchInsertQuery that can be executed with Execute().
// The columns parameter specifies which columns to insert.
func (qb *QueryBuilder) BatchInsert(table string, columns []string) *BatchInsertQuery {
    if len(columns) == 0 {
        return &BatchInsertQuery{err: ErrNoColumns}
    }
    // ...
}

๐Ÿ”„ Git Workflow

Branch Naming

Use descriptive branch names:

  • feature/batch-operations - New features
  • fix/cache-memory-leak - Bug fixes
  • docs/update-readme - Documentation updates
  • refactor/query-builder - Code refactoring
  • test/add-integration-tests - Test improvements

Commit Messages

Follow Conventional Commits:

<type>(<scope>): <description>

[optional body]

[optional footer]

Types:

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation only
  • style: Code style (formatting, missing semicolons, etc.)
  • refactor: Code refactoring
  • test: Adding or updating tests
  • chore: Maintenance tasks

Examples:

git commit -m "feat(batch): add batch UPDATE support"
git commit -m "fix(cache): prevent memory leak in LRU eviction"
git commit -m "docs: update README with UPSERT examples"
git commit -m "test(core): add integration tests for transactions"

Creating a Pull Request

  1. Create feature branch:

    git checkout main
    git pull upstream main
    git checkout -b feature/my-feature
    
  2. Make changes and commit:

    # Make changes...
    gofmt -w .
    go test ./...
    
    git add .
    git commit -m "feat: add my feature"
    
  3. Push to your fork:

    git push origin feature/my-feature
    
  4. Create PR on GitHub:

Pull Request Guidelines

PR Title: Use conventional commit format

feat(batch): add batch UPDATE support

PR Description must include:

  • Summary: What does this PR do?
  • Motivation: Why is this change needed?
  • Changes: List of changes made
  • Testing: How was this tested?
  • Breaking Changes: Any breaking changes? (if yes, must be major version)

Example PR Description:

## Summary
Adds batch UPDATE support for updating multiple rows with different values in a single query.

## Motivation
Users need to update many rows efficiently without individual UPDATE queries.

## Changes
- Added BatchUpdateQuery type
- Implemented CASE-WHEN SQL generation for all 3 dialects
- Added 25 unit tests
- Added 8 integration tests
- Updated README with examples

## Testing
- Unit tests: 25 new tests, all passing
- Integration tests: tested on PostgreSQL, MySQL, SQLite
- Benchmarks: 2.5x faster than individual UPDATEs

## Breaking Changes
None - backward compatible addition.

๐Ÿ› Reporting Bugs

Before Reporting

  1. Check existing issues
  2. Verify it's not already fixed in main
  3. Try with latest version

Bug Report Template

**Describe the bug**
A clear description of the bug.

**To Reproduce**
Steps to reproduce:
1. Create DB connection with...
2. Execute query...
3. See error

**Expected behavior**
What you expected to happen.

**Actual behavior**
What actually happened.

**Code Sample**
```go
// Minimal reproducible example
db, _ := relica.Open("postgres", dsn)
// ...

Environment:

  • Relica version: v0.1.0-beta
  • Go version: 1.25.0
  • OS: Ubuntu 22.04
  • Database: PostgreSQL 15

Additional context Any other relevant information.


---

## ๐Ÿ’ก Feature Requests

### Before Requesting

1. Check [existing issues](https://github.com/coregx/relica/issues)
2. Check [ROADMAP.md](ROADMAP.md) for planned features
3. Consider if it fits Relica's scope (lightweight, zero-dependency)

### Feature Request Template

```markdown
**Problem Statement**
What problem does this feature solve?

**Proposed Solution**
How should this feature work?

**Alternatives Considered**
What other approaches did you consider?

**Use Case**
Real-world example of how this would be used.

**Breaking Changes**
Would this require breaking changes?

๐Ÿ“š Documentation

Documentation Guidelines

  1. README.md: High-level overview, quick start, examples
  2. Godoc comments: All exported functions, types, constants
  3. CHANGELOG.md: All user-facing changes
  4. docs/reports/: Detailed implementation reports

Writing Good Documentation

  • Use clear, concise language
  • Include code examples
  • Explain why, not just what
  • Keep examples up-to-date with code
  • Test code examples (they should compile and run)

๐Ÿ“ฆ Internal Packages

Relica uses Go's internal/ package structure to maintain a clear public API boundary.

Understanding Internal Packages

What you need to know:

  1. Only import the main package:

    // โœ… Correct - Public API
    import "github.com/coregx/relica"
    
    // โŒ Wrong - Internal package (will not compile)
    import "github.com/coregx/relica/internal/core"
    
  2. All functionality is available through the main relica package via re-exports in db.go

  3. Internal packages are not part of the public API:

    • Changes to internal/ do NOT require major version bumps
    • We can refactor freely without breaking user code
    • Documentation on pkg.go.dev only shows the public API

Working with Internal Packages (Contributors)

When developing Relica:

  • Internal packages CAN import each other
  • Tests CAN import internal packages
  • Benchmarks CAN import internal packages
  • Only db.go should re-export to public API

Example internal import (in contributor code):

// internal/core/builder.go
package core

import (
    "github.com/coregx/relica/internal/cache"    // โœ… OK
    "github.com/coregx/relica/internal/dialects" // โœ… OK
)

Adding new public functionality:

  1. Implement in internal/core/ (or appropriate package)
  2. Export through db.go:
    // db.go
    type (
        NewType = core.NewType  // Re-export
    )
    
    var (
        NewFunc = core.NewFunc  // Re-export
    )
    
  3. Document in README.md
  4. Add example to docs/

Why Internal Packages?

  • API Stability: Changes to implementation don't break user code
  • Freedom to Refactor: Reorganize code without semver implications
  • Clear Documentation: pkg.go.dev shows only public API
  • Go Best Practice: Standard pattern for Go libraries (used by GORM, stdlib packages, etc.)

See docs/reports/INTERNAL_VS_NO_INTERNAL_2025.md for detailed analysis.


๐ŸŽฏ Release Process

See RELEASE_GUIDE.md for detailed release process.

Summary:

  1. Feature branches created from main
  2. PRs merged to main
  3. CI passes on main
  4. Triple-check: branch, tag order, CHANGELOG
  5. Create tag: git tag -a v0.X.X
  6. Push tag: git push origin v0.X.X

Only maintainers can create releases.


๐Ÿ† Recognition

Contributors are recognized in:

  • CHANGELOG.md (for significant contributions)
  • GitHub contributors page
  • Release notes

โ“ Questions?


๐Ÿ“œ Code of Conduct

See CODE_OF_CONDUCT.md for community guidelines.


Thank you for contributing to Relica! ๐ŸŽ‰

Every contribution, no matter how small, helps make Relica better for everyone.