faucet_cli/catalog/spec.rs
1//! Serde config types for the top-level `catalog:` block (#279).
2
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6fn default_sample_records() -> usize {
7 100
8}
9
10/// The top-level `catalog:` block: opts a `faucet run` / `schedule` /
11/// `replicate` pipeline into recording the Data Movement Catalog after every
12/// successful root invocation. `faucet serve` records into its `--history`
13/// backend automatically — this block is for the non-serve runtimes (and for
14/// `faucet catalog`, which reads the same store).
15#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
16#[serde(deny_unknown_fields)]
17pub struct CatalogSpec {
18 /// Where the catalog is stored: `sqlite:<path>` (e.g.
19 /// `sqlite:./faucet-catalog.db`), a `postgres://…` URL, or `memory`
20 /// (process-lifetime only — useful for tests). SQL backends require the
21 /// matching `serve-history-sqlite` / `serve-history-postgres` build
22 /// feature. Point `faucet serve --history` at the same URL to browse the
23 /// accumulated catalog in the control plane + web console.
24 pub url: String,
25
26 /// How many records to sample per run for schema inference (per side).
27 /// The sample bounds memory; the schema timeline only ever stores the
28 /// inferred schema, never the records.
29 #[serde(default = "default_sample_records")]
30 pub sample_records: usize,
31}
32
33#[cfg(test)]
34mod tests {
35 use super::*;
36
37 #[test]
38 fn parses_minimal_block_with_defaults() {
39 let spec: CatalogSpec = serde_yaml::from_str("url: sqlite:./cat.db").unwrap();
40 assert_eq!(spec.url, "sqlite:./cat.db");
41 assert_eq!(spec.sample_records, 100);
42 }
43
44 #[test]
45 fn rejects_unknown_fields() {
46 let err = serde_yaml::from_str::<CatalogSpec>("url: memory\nnope: 1").unwrap_err();
47 assert!(err.to_string().contains("nope"));
48 }
49
50 #[test]
51 fn schema_generates() {
52 let schema = schemars::schema_for!(CatalogSpec);
53 let v = serde_json::to_value(&schema).unwrap();
54 assert!(v["properties"]["url"].is_object());
55 }
56}