1use crate::files::{SqlContent, SqlContentSet};
3use std::{
4 io,
5 path::{Path, PathBuf},
6};
7
8#[derive(Debug)]
10pub struct SqlSource {
11 path: Option<PathBuf>,
12 content: String,
13}
14
15impl SqlSource {
16 pub fn from_path(path: &Path) -> io::Result<Self> {
21 let source = SqlContent::from_path(path)?;
22 let content = source.content().to_owned();
23 Ok(Self { path: Some(path.to_owned()), content })
24 }
25
26 #[must_use]
28 pub const fn from_str(content: String, path: Option<PathBuf>) -> Self {
29 Self { path, content }
30 }
31
32 #[must_use]
34 pub fn path(&self) -> Option<&Path> {
35 self.path.as_deref()
36 }
37 #[must_use]
39 pub fn path_into_path_buf(&self) -> Option<PathBuf> {
40 self.path.clone()
41 }
42
43 #[must_use]
45 pub fn content(&self) -> &str {
46 &self.content
47 }
48
49 pub fn sql_sources(path: &Path, deny_list: &[String]) -> io::Result<Vec<Self>> {
62 let sql_content_set = SqlContentSet::new(path, deny_list)?;
63
64 let files_contents = sql_content_set
65 .iter()
66 .map(|p| Self::from_path(p.path()))
67 .collect::<io::Result<Vec<_>>>()?;
68
69 Ok(files_contents)
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use std::{env, fs, path::PathBuf};
76
77 use crate::source::SqlSource;
78
79 #[test]
80 fn test_sql_file_read() -> Result<(), Box<dyn std::error::Error>> {
81 let base = env::temp_dir().join("recursive_scan_test3");
82 let _ = fs::remove_dir_all(&base);
83 fs::create_dir_all(&base)?;
84 let sub = base.join("subdir");
85 fs::create_dir_all(&sub)?;
86 let file1 = base.join("one.sql");
87 let file2 = sub.join("two.sql");
88 let non_sql1 = base.join("ignore.txt");
89 let non_sql2 = sub.join("README.md");
90 fs::File::create(&file1)?;
91 fs::File::create(&file2)?;
92 fs::File::create(&non_sql1)?;
93 fs::File::create(&non_sql2)?;
94 let sql_statement = "CREATE TABLE users( id INTEGER PRIMARY KEY);";
95 fs::write(&file1, sql_statement)?;
96 fs::write(&file2, sql_statement)?;
97 let mut expected = vec![&file1, &file2];
98 expected.sort();
99 let mut found: Vec<&PathBuf> = Vec::new();
100 let sql_file_set = SqlSource::sql_sources(&base, &[])?;
101 for file in &sql_file_set {
102 assert_eq!(file.content, sql_statement);
103 if let Some(p) = &file.path {
104 found.push(p);
105 }
106 }
107 assert_eq!(found, expected);
108 let _ = fs::remove_dir_all(&base);
109 Ok(())
110 }
111
112 #[test]
113 fn test_sql_file_new_from_str_has_no_path_and_preserves_content() {
114 let sql = "SELECT * FROM users;";
115 let file = SqlSource::from_str(sql.to_owned(), None);
116 assert!(file.path().is_none());
117 assert!(file.path_into_path_buf().is_none());
118 assert_eq!(file.content(), sql);
119 }
120}