Skip to content

Commit 37f1062

Browse files
committed
Tooling: Add index DB query tool
- For a long time we've had a need for this tool, finally we have it! - With docs
1 parent 67684bb commit 37f1062

File tree

7 files changed

+92
-2
lines changed

7 files changed

+92
-2
lines changed

AGENTS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ Core structure:
6161
`~/Library/Logs/com.veszelovszki.cmdr/`. Full reference with `RUST_LOG` recipes:
6262
[docs/tooling/logging.md](docs/tooling/logging.md).
6363
- **Hot reload**: `pnpm dev` hot-reloads. Max 15s for Rust, max 3s for frontend.
64+
- **Index DB queries**: The index SQLite DB uses a custom `platform_case` collation, so the `sqlite3` CLI can't query
65+
it. Use `cargo run --bin index_query -- <db_path> "<sql>"` instead. See
66+
[`src-tauri/src/bin/CLAUDE.md`](apps/desktop/src-tauri/src/bin/CLAUDE.md) for examples and DB paths.
6467

6568
## MCP
6669

apps/desktop/src-tauri/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ automation = ["dep:tauri-plugin-automation"]
1616
name = "Cmdr"
1717
path = "src/main.rs"
1818

19+
[[bin]]
20+
name = "index_query"
21+
path = "src/bin/index_query.rs"
22+
1923
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
2024

2125
[lib]
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Dev binaries
2+
3+
Cargo binary targets that depend on `cmdr_lib`. Source lives here because Cargo requires `[[bin]]` sources under the package root.
4+
5+
## index_query
6+
7+
Query the drive index SQLite database with the `platform_case` collation registered. The standard `sqlite3` CLI can't query these DBs because the custom collation isn't available.
8+
9+
```sh
10+
cargo run --bin index_query -- <db_path> "<sql>"
11+
```
12+
13+
DB paths:
14+
- **Dev**: `~/Library/Application Support/com.veszelovszki.cmdr-dev/index-root.db`
15+
- **Prod**: `~/Library/Application Support/com.veszelovszki.cmdr/index-root.db`
16+
17+
Examples:
18+
19+
```sh
20+
# List top-level directories
21+
cargo run --bin index_query -- ~/Library/Application\ Support/com.veszelovszki.cmdr-dev/index-root.db \
22+
"SELECT e.id, e.name, ds.recursive_size FROM entries e LEFT JOIN dir_stats ds ON ds.entry_id = e.id WHERE e.parent_id = 1 AND e.is_directory = 1 ORDER BY e.name"
23+
24+
# Check dir_stats coverage
25+
cargo run --bin index_query -- ~/Library/Application\ Support/com.veszelovszki.cmdr-dev/index-root.db \
26+
"SELECT (SELECT count(*) FROM dir_stats) as has_stats, (SELECT count(*) FROM entries WHERE is_directory = 1) as total_dirs"
27+
28+
# Walk a specific path (resolve component by component)
29+
cargo run --bin index_query -- ~/Library/Application\ Support/com.veszelovszki.cmdr-dev/index-root.db \
30+
"SELECT id, name FROM entries WHERE parent_id = 1 AND name = 'Users'"
31+
```
32+
33+
Output is tab-separated with a header row (like `sqlite3` default mode).
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//! Minimal CLI to query the Cmdr index SQLite database.
2+
//!
3+
//! The index DB uses a custom `platform_case` collation on the `name` column,
4+
//! so the standard `sqlite3` CLI can't query it. This tool registers the
5+
//! collation and runs an arbitrary SQL query.
6+
//!
7+
//! Usage: cargo run --bin index_query -- <db_path> <sql>
8+
9+
use rusqlite::{Connection, OpenFlags};
10+
11+
fn main() {
12+
let args: Vec<String> = std::env::args().collect();
13+
if args.len() != 3 {
14+
eprintln!("Usage: {} <db_path> <sql>", args[0]);
15+
std::process::exit(1);
16+
}
17+
let db_path = &args[1];
18+
let sql = &args[2];
19+
20+
let conn =
21+
Connection::open_with_flags(db_path, OpenFlags::SQLITE_OPEN_READ_ONLY).expect("Couldn't open database");
22+
cmdr_lib::indexing::store::register_platform_case_collation(&conn).expect("Couldn't register collation");
23+
24+
let mut stmt = conn.prepare(sql).expect("Couldn't prepare statement");
25+
let column_count = stmt.column_count();
26+
27+
// Print header row
28+
let headers: Vec<&str> = (0..column_count).map(|i| stmt.column_name(i).unwrap_or("?")).collect();
29+
println!("{}", headers.join("\t"));
30+
31+
// Print data rows
32+
let mut rows = stmt.query([]).expect("Couldn't execute query");
33+
while let Some(row) = rows.next().expect("Couldn't read row") {
34+
let values: Vec<String> = (0..column_count)
35+
.map(|i| {
36+
row.get::<_, rusqlite::types::Value>(i)
37+
.map(|v| match v {
38+
rusqlite::types::Value::Null => "NULL".to_string(),
39+
rusqlite::types::Value::Integer(n) => n.to_string(),
40+
rusqlite::types::Value::Real(f) => f.to_string(),
41+
rusqlite::types::Value::Text(s) => s,
42+
rusqlite::types::Value::Blob(b) => format!("<blob {} bytes>", b.len()),
43+
})
44+
.unwrap_or_else(|_| "ERROR".to_string())
45+
})
46+
.collect();
47+
println!("{}", values.join("\t"));
48+
}
49+
}

apps/desktop/src-tauri/src/indexing/store.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ impl std::error::Error for IndexStoreError {}
205205
///
206206
/// Must be called on every connection before any table creation or query,
207207
/// because custom collations are not persisted in the DB file.
208-
fn register_platform_case_collation(conn: &Connection) -> Result<(), IndexStoreError> {
208+
pub fn register_platform_case_collation(conn: &Connection) -> Result<(), IndexStoreError> {
209209
conn.create_collation("platform_case", platform_case_compare)?;
210210
Ok(())
211211
}

apps/desktop/src-tauri/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ mod file_system;
8080
pub(crate) mod file_viewer;
8181
mod font_metrics;
8282
pub mod icons;
83-
mod indexing;
83+
pub mod indexing;
8484
pub mod licensing;
8585
#[cfg(target_os = "linux")]
8686
pub(crate) mod linux_distro;

docs/architecture.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ Dev workflow docs and external service references. All in `docs/tooling/`.
122122
|-----|---------|
123123
| [logging.md](tooling/logging.md) | Unified logging, `RUST_LOG` recipes for every subsystem |
124124
| [css-health-checks.md](tooling/css-health-checks.md) | Stylelint + Go-based unused CSS checker |
125+
| [src-tauri/src/bin/CLAUDE.md](../apps/desktop/src-tauri/src/bin/CLAUDE.md) | `index_query` — query index DB with `platform_case` collation (`sqlite3` can't) |
125126

126127
The check runner and E2E testing docs live colocated with their code:
127128
- Check runner: [`scripts/check/CLAUDE.md`](../scripts/check/CLAUDE.md)

0 commit comments

Comments
 (0)