sqlite_graphrag/print_schema.rs
1//! Agent-native R-AN-01: emit a command's JSON Schema and exit without work.
2//!
3//! When a subcommand is invoked with `--print-schema`, the handler must write
4//! the corresponding file from `docs/schemas/*.schema.json` to stdout as
5//! **compact** JSON and return successfully without opening the database,
6//! calling an LLM, or performing other side effects.
7//!
8//! Schemas are embedded at compile time so the installed binary does not
9//! depend on a source-tree checkout.
10
11use crate::errors::AppError;
12use crate::output;
13
14/// Identifiers for schemas that currently support `--print-schema`.
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum SchemaId {
17 /// `list` → `docs/schemas/list.schema.json`
18 List,
19 /// `recall` → `docs/schemas/recall.schema.json`
20 Recall,
21 /// `enrich --status` → `docs/schemas/enrich-status.schema.json`
22 EnrichStatus,
23 /// `config list` → `docs/schemas/config-list.schema.json`
24 ConfigList,
25}
26
27impl SchemaId {
28 /// Human-readable command name for error messages.
29 pub const fn name(self) -> &'static str {
30 match self {
31 Self::List => "list",
32 Self::Recall => "recall",
33 Self::EnrichStatus => "enrich-status",
34 Self::ConfigList => "config-list",
35 }
36 }
37
38 /// Embedded pretty JSON Schema source (from the repository at build time).
39 const fn embedded(self) -> &'static str {
40 match self {
41 Self::List => include_str!("../docs/schemas/list.schema.json"),
42 Self::Recall => include_str!("../docs/schemas/recall.schema.json"),
43 Self::EnrichStatus => include_str!("../docs/schemas/enrich-status.schema.json"),
44 Self::ConfigList => include_str!("../docs/schemas/config-list.schema.json"),
45 }
46 }
47}
48
49/// Emit the compact JSON Schema for `id` to stdout and flush.
50///
51/// Stdout contains only the schema document (one compact JSON line) so agents
52/// can pipe the output into a validator without filtering tracing noise.
53///
54/// # Errors
55/// Returns [`AppError::Validation`] if the embedded schema is not valid JSON
56/// (should never happen for the checked-in files) or an I/O error from stdout.
57pub fn emit(id: SchemaId) -> Result<(), AppError> {
58 let value: serde_json::Value = serde_json::from_str(id.embedded()).map_err(|e| {
59 AppError::Validation(crate::i18n::validation::embedded_schema_invalid_json(
60 id.name(),
61 &e,
62 ))
63 })?;
64 // Compact form: strip pretty-print whitespace from the source files.
65 output::emit_json_compact(&value)
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn embedded_schemas_parse_as_json_objects() {
74 for id in [
75 SchemaId::List,
76 SchemaId::Recall,
77 SchemaId::EnrichStatus,
78 SchemaId::ConfigList,
79 ] {
80 let v: serde_json::Value =
81 serde_json::from_str(id.embedded()).unwrap_or_else(|e| panic!("{}: {e}", id.name()));
82 assert!(v.is_object(), "{} schema must be a JSON object", id.name());
83 assert!(
84 v.get("$schema").is_some() || v.get("type").is_some(),
85 "{} schema must look like a JSON Schema document",
86 id.name()
87 );
88 }
89 }
90}