context_harness/
get.rs

1//! Document retrieval by ID.
2//!
3//! Fetches a full document and its associated chunks from the database
4//! via [`SqliteStore`]. Used by both the `ctx get` CLI command and the
5//! `POST /tools/get` HTTP endpoint.
6//!
7//! # Usage
8//!
9//! ```bash
10//! # Retrieve a document by UUID
11//! ctx get 550e8400-e29b-41d4-a716-446655440000
12//! ```
13//!
14//! # Response Shape
15//!
16//! The response matches the `context.get` schema defined in `docs/SCHEMAS.md`,
17//! including full document metadata, body text, and all chunks ordered by index.
18
19use anyhow::{bail, Result};
20
21use context_harness_core::store::Store;
22#[allow(unused_imports)]
23pub use context_harness_core::store::{ChunkResponse, DocumentResponse};
24
25use crate::config::Config;
26use crate::db;
27use crate::sqlite_store::SqliteStore;
28
29/// Retrieves a document by its UUID, including all associated chunks.
30///
31/// This is the core retrieval function used by both the CLI (`ctx get`)
32/// and the HTTP server (`POST /tools/get`).
33pub async fn get_document(config: &Config, id: &str) -> Result<DocumentResponse> {
34    let pool = db::connect(config).await?;
35    let store = SqliteStore::new(pool.clone());
36
37    let result = store.get_document(id).await?;
38    pool.close().await;
39
40    match result {
41        Some(doc) => Ok(doc),
42        None => bail!("document not found: {}", id),
43    }
44}
45
46/// CLI entry point for `ctx get <id>`.
47pub async fn run_get(config: &Config, id: &str) -> Result<()> {
48    let doc = match get_document(config, id).await {
49        Ok(d) => d,
50        Err(e) => {
51            eprintln!("Error: {}", e);
52            std::process::exit(1);
53        }
54    };
55
56    println!("--- Document ---");
57    println!("id:           {}", doc.id);
58    println!(
59        "title:        {}",
60        doc.title.as_deref().unwrap_or("(untitled)")
61    );
62    println!("source:       {}", doc.source);
63    println!("source_id:    {}", doc.source_id);
64    if let Some(ref url) = doc.source_url {
65        println!("source_url:   {}", url);
66    }
67    if let Some(ref auth) = doc.author {
68        println!("author:       {}", auth);
69    }
70    println!("created_at:   {}", doc.created_at);
71    println!("updated_at:   {}", doc.updated_at);
72    println!("content_type: {}", doc.content_type);
73    println!("metadata:     {}", doc.metadata);
74    println!();
75
76    println!("--- Body ---");
77    println!("{}", doc.body);
78    println!();
79
80    println!("--- Chunks ({}) ---", doc.chunks.len());
81    for chunk in &doc.chunks {
82        println!("[chunk {}]", chunk.index);
83        println!("{}", chunk.text);
84        println!();
85    }
86
87    Ok(())
88}