1use anyhow::{Context, Result};
4use flowscope_core::FileSource;
5use std::io::{self, Read};
6use std::path::PathBuf;
7
8pub fn read_input(files: &[PathBuf]) -> Result<Vec<FileSource>> {
13 if files.is_empty() {
14 read_from_stdin()
15 } else {
16 read_from_files(files)
17 }
18}
19
20fn read_from_stdin() -> Result<Vec<FileSource>> {
22 let mut content = String::new();
23 io::stdin()
24 .read_to_string(&mut content)
25 .context("Failed to read from stdin")?;
26
27 Ok(vec![FileSource {
28 name: "<stdin>.sql".to_string(),
30 content,
31 }])
32}
33
34fn read_from_files(files: &[PathBuf]) -> Result<Vec<FileSource>> {
36 files
37 .iter()
38 .map(|path| {
39 let content = std::fs::read_to_string(path)
40 .with_context(|| format!("Failed to read file: {}", path.display()))?;
41
42 Ok(FileSource {
43 name: path.display().to_string(),
44 content,
45 })
46 })
47 .collect()
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53 use std::io::Write;
54 use tempfile::NamedTempFile;
55
56 #[test]
57 fn test_read_single_file() {
58 let mut file = NamedTempFile::new().unwrap();
59 writeln!(file, "SELECT * FROM users").unwrap();
60
61 let sources = read_from_files(&[file.path().to_path_buf()]).unwrap();
62 assert_eq!(sources.len(), 1);
63 assert!(sources[0].content.contains("SELECT * FROM users"));
64 }
65
66 #[test]
67 fn test_read_multiple_files() {
68 let mut file1 = NamedTempFile::new().unwrap();
69 let mut file2 = NamedTempFile::new().unwrap();
70 writeln!(file1, "SELECT * FROM users").unwrap();
71 writeln!(file2, "SELECT * FROM orders").unwrap();
72
73 let sources =
74 read_from_files(&[file1.path().to_path_buf(), file2.path().to_path_buf()]).unwrap();
75 assert_eq!(sources.len(), 2);
76 }
77
78 #[test]
79 fn test_read_missing_file() {
80 let result = read_from_files(&[PathBuf::from("/nonexistent/file.sql")]);
81 assert!(result.is_err());
82 }
83}