bear-query 0.0.3

A read-only Rust library for querying the Bear note-taking app's SQLite database with minimal interference
Documentation
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

`bear-query` is a read-only Rust library for querying the Bear note-taking app's SQLite database. The library is designed to minimize interference with Bear's operations while it's running.

## Core Architecture

### Short-Lived Connection Pattern

**Critical Design Principle**: This library uses short-lived database connections to avoid blocking Bear's write operations. Bear does NOT use SQLite's WAL (Write-Ahead Logging) mode, so connection management is critical.

The architecture is built around a single private method:

- `BearDb::with_connection<F, R>(&self, f: F)` - The ONLY place where database connections are opened
  - Opens connection with `SQLITE_OPEN_READ_ONLY | SQLITE_OPEN_NO_MUTEX`
  - Sets busy timeout to 5000ms
  - Enables `PRAGMA query_only = ON`
  - Executes closure with connection reference
  - Automatically closes connection when closure returns

All public methods (`tags()`, `note()`, `notes()`, `note_links()`, `note_tags()`) internally call `with_connection()` and should never hold connections longer than necessary.

### Database Schema & Normalization

Bear uses Core Data with SQLite persistence. The underlying schema uses Core Data conventions:
- Table names prefixed with `Z` (e.g., `ZSFNOTE`, `ZSFNOTETAG`)
- Column names prefixed with `Z` (e.g., `Z_PK`, `ZTITLE`)
- Junction table columns with numbers (e.g., `Z_5NOTES`, `Z_13TAGS`)
- Timestamps as seconds since 2001-01-01 (Core Data epoch)

#### Normalized Schema Layer

The library provides a normalization layer through automatically-generated Common Table Expressions (CTEs). This abstracts Bear's quirks and provides clean table names:

**Normalized Tables:**
- `notes` - Normalized view of `ZSFNOTE` (all note fields with clean names)
- `tags` - Normalized view of `ZSFNOTETAG` (tag IDs and names)
- `note_tags` - Normalized view of `Z_5TAGS` junction table (note_id, tag_id)
- `note_links` - Normalized view of `ZSFNOTEBACKLINK` (from_note_id, to_note_id)

**Key Transformations:**
1. **Timestamps**: Core Data epoch (2001-01-01) → SQLite datetime format
2. **Column Names**: `Z_PK``id`, `ZTITLE``title`, `ZTEXT``content`, etc.
3. **Boolean Fields**: `ZTRASHED``is_trashed`, `ZARCHIVED``is_archived`, `ZPINNED``is_pinned`
4. **Junction Columns**: Dynamically discovered numbered columns → `note_id`, `tag_id`

#### Schema Discovery

At initialization (`BearDb::new()`):
1. Opens temporary read-only connection
2. Queries `PRAGMA table_info(Z_5TAGS)` to discover junction column names
3. Generates normalizing CTE SQL based on discovered schema
4. Caches CTE string in `BearDb` for all subsequent queries
5. Closes connection

#### Queryable Abstraction

All database operations go through the `Queryable<'a>` wrapper:
- Wraps the raw SQLite `Connection`
- Automatically prepends normalizing CTEs to all queries
- Used by both typed methods (`tags()`, `notes()`, etc.) and generic `query()` API

For complete schema documentation, see `SCHEMA.md` in the repository root.

## Development Commands

### Building
```bash
cargo build          # Debug build
cargo build --release # Release build
```

### Running
```bash
cargo run            # Runs src/main.rs example
```

### Documentation
```bash
cargo doc --no-deps  # Generate library docs
```

### Testing
This project uses `cargo-nextest` as the test runner for better performance and output:
```bash
cargo nextest run              # Run all tests
cargo nextest run test_name    # Run specific test
cargo test --doc               # Run doc tests (nextest doesn't support these yet)
```

If you need to install nextest:
```bash
cargo install cargo-nextest
```

## Code Conventions

### Module System
- **ALWAYS use the modern flat module system** - declare modules with `mod module_name;` in parent files
- **NEVER create `mod.rs` files** - this is the old Rust 2015 module system
- Module files should be named directly (e.g., `src/schema.rs`, `src/dataframe.rs`)
- Submodules within a directory should use the parent file pattern (e.g., `src/schema.rs` declares submodules, not `src/schema/mod.rs`)

### No Standard Output in Library Code
- NEVER use `eprintln!`, `println!`, or similar in lib.rs
- Library code should be silent; output is only acceptable in main.rs or examples

### Connection Safety Rules
1. Never add a persistent connection field to `BearDb`
2. All database operations must go through `with_connection()`
3. The 5000ms busy timeout should not be changed without careful consideration
4. Never remove the read-only flags or query_only pragma

## Checklists

When making significant changes, use these checklists to ensure everything stays in sync:

- **`SCHEMA_CHANGES.md`** - Comprehensive checklist for schema/column changes
- **`DOCUMENTATION.md`** - Quick reference for keeping documentation updated

Always review the appropriate checklist before submitting changes.