CLAUDE.mdrust

prql CLAUDE.md

Use a tiered testing approach—iterate quickly, validate thoroughly:

View Source

Claude

Development Workflow

Use a tiered testing approach—iterate quickly, validate thoroughly:

Inner loop (during development, ~5s):

# Fast tests on core packages
task prqlc:test

# Filtered by test name
cargo insta test -p prqlc --lib -- resolver
cargo insta test -p prqlc --test integration -- date

Before returning to user (~30s):

# Comprehensive prqlc tests - sufficient for most changes
task prqlc:pull-request

Cross-binding changes only (~2min):

# Only when changes affect JS/Python/wasm bindings
task test-all

The test suite is configured to minimize token usage:

  • Nextest only shows failures and slow tests (not 600 PASS lines)
  • Cargo builds use --quiet flag (no compilation spam)
  • Result: ~52% reduction in output (1128 → 540 lines, ~4.5k tokens)

Tests

Prefer inline snapshots for almost all tests:

insta::assert_snapshot!(result, @"expected output");

Initialize tests with empty snapshots, then run with --accept:

insta::assert_snapshot!(result, @"");

The test commands above with --accept will fill in the result automatically.

Test Strategy

Prefer small inline insta snapshot tests over full integration tests:

  • Use inline tests for most bug fixes and small features

    • Add #[test] functions in a #[cfg(test)] module at the end of the file
    • Use insta::assert_snapshot! for compact, readable test assertions
    • Fast to run, easy to review in PRs
  • Use integration tests (prqlc/tests/integration/queries/*.prql) only when:

    • Developing large, complex features that need comprehensive testing
    • Testing end-to-end behavior across multiple compilation stages
    • The test requires external resources or multi-file scenarios

Example of a good inline test:

#[cfg(test)]
mod test {
    use insta::assert_snapshot;

    #[test]
    fn test_my_feature() {
        let query = "from employees | filter country == 'USA'";
        assert_snapshot!(crate::tests::compile(query).unwrap(), @"");
    }
}

Running the CLI

For viewing prqlc output, for any stage of the compilation process:

# Compile PRQL to SQL
cargo run -p prqlc -- compile "from employees | filter country == 'USA'"

# Format PRQL code
cargo run -p prqlc -- fmt "from employees | filter country == 'USA'"

# See all available commands
cargo run -p prqlc -- --help

Linting

Run all lints with

task lint

Error Handling

Never panic on user input or recoverable errors. Use proper error returns:

  • .unwrap() on operations that can fail with user input
  • ? operator or return Err(Error::new_simple("message"))
  • .expect("reason") or unreachable!() only for compiler-bug invariants

Error Messages

Error messages should avoid 2nd person (you/your). Use softer modal verbs like "might" for a friendlier tone:

  • ❌ "are you missing from statement?" → ✅ "from statement might be missing?"
  • ❌ "did you forget to specify the column name?" → ✅ "column name might be missing?"
  • ❌ "you can only use X" → ✅ "X requires Y" (for hard constraints)
  • ❌ "Have you forgotten an argument?" → ✅ "Argument might be missing?"

Documentation

For Claude to view crate documentation:

# Build documentation for a specific crate
cargo doc -p prqlc

# View the generated HTML documentation with the View tool
# The docs are generated at target/doc/{crate_name}/index.html
View target/doc/prqlc/index.html

# For specific module documentation
View target/doc/prqlc/module_name/index.html

# For function documentation
View target/doc/prqlc/fn.compile.html

Releases & Environment

For releases or environment issues, see web/book/src/project/contributing/development.md.