PRQL is a modern language for transforming data β a simple, powerful, pipelined SQL replacement
# Claude
## Development Workflow
Use a tiered testing approachβiterate quickly, validate thoroughly:
**Inner loop** (during development, ~5s):
```sh
# 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):
```sh
# Comprehensive prqlc tests - sufficient for most changes
task prqlc:pull-request
```
**Cross-binding changes only** (~2min):
```sh
# 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:
```rust
insta::assert_snapshot!(result, @"expected output");
```
Initialize tests with empty snapshots, then run with `--accept`:
```rust
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/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:
```rust
#[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:
```sh
# 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
```sh
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:
```sh
# Build documentation for a specific crate
cargo doc -p prqlc
# Read the generated HTML documentation with the Read tool
# The docs are generated at target/doc/{crate_name}/index.html
Read target/doc/prqlc/index.html
# For specific module documentation
Read target/doc/prqlc/module_name/index.html
# For function documentation
Read target/doc/prqlc/fn.compile.html
```
## Releases & Environment
For releases or environment issues, see
`web/book/src/project/contributing/development.md`.