1use async_trait::async_trait;
18use lunaris_core::LunarisError;
19use ulid::Ulid;
20
21use crate::Extractor;
22use crate::types::{ChunkInput, RawExtraction, RawExtractionBatch};
23
24#[derive(Debug, Clone, Copy, Default)]
28pub struct NoopExtractor;
29
30#[async_trait]
31impl Extractor for NoopExtractor {
32 async fn extract(
33 &self,
34 _episode_id: Ulid,
35 chunks: &[ChunkInput],
36 ) -> Result<RawExtractionBatch, LunarisError> {
37 Ok(RawExtractionBatch {
38 by_chunk: chunks
39 .iter()
40 .map(|c| RawExtraction {
41 source_chunk_id: c.chunk_id,
42 entities: Vec::new(),
43 relations: Vec::new(),
44 facts: Vec::new(),
45 })
46 .collect(),
47 })
48 }
49
50 fn applies(&self) -> bool {
51 false
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58
59 #[tokio::test]
60 async fn noop_returns_empty_extractions() {
61 let chunks = vec![
62 ChunkInput {
63 chunk_id: Ulid::new(),
64 text: "hello world".into(),
65 heading_path: vec!["intro".into()],
66 reference_time_iso: None,
67 },
68 ChunkInput {
69 chunk_id: Ulid::new(),
70 text: "second chunk".into(),
71 heading_path: vec![],
72 reference_time_iso: None,
73 },
74 ];
75 let extracted = NoopExtractor.extract(Ulid::new(), &chunks).await.unwrap();
76 assert_eq!(extracted.by_chunk.len(), 2);
77 for (i, r) in extracted.by_chunk.iter().enumerate() {
78 assert_eq!(r.source_chunk_id, chunks[i].chunk_id);
79 assert!(r.entities.is_empty());
80 assert!(r.relations.is_empty());
81 assert!(r.facts.is_empty());
82 }
83 }
84
85 #[tokio::test]
86 async fn noop_handles_empty_input_batch() {
87 let extracted = NoopExtractor.extract(Ulid::new(), &[]).await.unwrap();
88 assert!(extracted.by_chunk.is_empty());
89 }
90
91 #[test]
92 fn noop_applies_is_false() {
93 assert!(!NoopExtractor.applies(), "NoopExtractor::applies must be false");
94 }
95}