Skip to content

Commit 098ebb0

Browse files
committed
added method to parse str with an associated Path
1 parent 1539a5a commit 098ebb0

4 files changed

Lines changed: 124 additions & 22 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "sql_docs"
3-
version = "1.0.8"
3+
version = "1.0.9"
44
edition = "2024"
55
description = "A crate for parsing comments from sql files and using them for documentation generation"
66
documentation = "https://docs.rs/sql_docs"

src/files.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,22 +53,22 @@ impl SqlFilesList {
5353
/// Returns an [`io::Error`] if directory traversal fails.
5454
pub fn new<P: AsRef<Path>>(path: P, deny_list: &[String]) -> io::Result<Self> {
5555
let recursive_scan = recursive_dir_scan(path.as_ref())?;
56-
let allow_list = {
56+
let mut allow_list: Vec<PathBuf> = {
5757
let deny = DenyList::new(deny_list);
5858
recursive_scan.into_iter().filter(|p| !deny.deny_files().contains(p)).collect()
5959
};
60-
60+
allow_list.sort();
6161
Ok(Self { sql_files: allow_list })
6262
}
6363

6464
/// Returns discovered `.sql` files in discovery order (filesystem-dependent).
6565
#[must_use]
66-
pub fn sql_files(&self) -> Vec<&PathBuf> {
67-
let mut files: Vec<&PathBuf> = self.sql_files.iter().collect();
66+
pub fn sql_files(&self) -> Vec<PathBuf> {
67+
let mut files: Vec<PathBuf> =
68+
self.sql_files.iter().map(std::borrow::ToOwned::to_owned).collect();
6869
files.sort();
6970
files
7071
}
71-
7272
}
7373

7474
impl From<SqlFilesList> for Vec<PathBuf> {
@@ -252,7 +252,7 @@ mod tests {
252252
fs::File::create(&non_sql1)?;
253253
fs::File::create(&non_sql2)?;
254254
let sql_file_list = SqlFilesList::new(&base, &[])?;
255-
let mut expected = vec![&file1, &file2];
255+
let mut expected = vec![file1, file2];
256256
expected.sort();
257257
assert_eq!(sql_file_list.sql_files(), expected);
258258
let _ = fs::remove_dir_all(&base);
@@ -309,8 +309,8 @@ mod tests {
309309
fs::File::create(&non_sql2)?;
310310
let deny_list = &[file1.to_string_lossy().to_string()];
311311
let sql_file_list = SqlFilesList::new(&base, deny_list)?;
312-
let found = sql_file_list.sql_files_sorted();
313-
let mut expected = vec![&file2];
312+
let found = sql_file_list.sql_files();
313+
let mut expected = vec![file2];
314314
expected.sort();
315315
assert_eq!(found, expected);
316316
let _ = fs::remove_dir_all(&base);
@@ -352,16 +352,16 @@ mod tests {
352352
fs::File::create(&file2)?;
353353
fs::File::create(&noise)?;
354354
let sql_file_list = SqlFilesList::new(&base, &[])?;
355-
let expected: Vec<PathBuf> = sql_file_list.sql_files().to_vec();
355+
let expected: Vec<PathBuf> = sql_file_list.sql_files();
356356
let got: Vec<PathBuf> = Vec::from(sql_file_list);
357357
assert_eq!(got, expected);
358358
let _ = fs::remove_dir_all(&base);
359359
Ok(())
360360
}
361361
#[test]
362362
fn test_sql_file_new_from_str_has_no_path_and_preserves_content() {
363-
let sql = "SELECT * FROM users;".to_owned();
364-
let file = SqlFile::new_from_str(sql.clone());
363+
let sql = "SELECT * FROM users;";
364+
let file = SqlFile::new_from_str(sql.to_owned(), None);
365365
assert!(file.path().is_none());
366366
assert!(file.path_into_path_buf().is_none());
367367
assert_eq!(file.content(), sql);

src/sql_doc.rs

Lines changed: 111 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
33
use std::{
44
path::{Path, PathBuf},
5-
str::FromStr, vec,
5+
str::FromStr,
6+
vec,
67
};
78

89
use crate::{
@@ -49,7 +50,7 @@ enum SqlFileDocSource<'a> {
4950
File(PathBuf),
5051
Files(Vec<PathBuf>),
5152
FromString(&'a str),
52-
FromStringsWithPaths(&'a[(String, PathBuf)])
53+
FromStringsWithPaths(&'a [(String, PathBuf)]),
5354
}
5455

5556
impl SqlDoc {
@@ -100,14 +101,15 @@ impl SqlDoc {
100101

101102
/// Creates a builder from a vec of tuples containing the `sql` as [`String`] and the path as [`PathBuf`]
102103
#[must_use]
103-
pub const fn builder_from_strs_with_paths(string_with_path: &[(String, PathBuf)]) -> SqlDocBuilder<'_> {
104+
pub const fn builder_from_strs_with_paths(
105+
string_with_path: &[(String, PathBuf)],
106+
) -> SqlDocBuilder<'_> {
104107
SqlDocBuilder {
105108
source: SqlFileDocSource::FromStringsWithPaths(string_with_path),
106109
deny: Vec::new(),
107-
multiline_flat: MultiFlatten::NoFlat
110+
multiline_flat: MultiFlatten::NoFlat,
108111
}
109112
}
110-
111113

112114
/// Method for finding a specific [`TableDoc`] by `name`
113115
///
@@ -223,8 +225,10 @@ impl SqlDocBuilder<'_> {
223225
SqlFileDocSource::FromString(content) => {
224226
let sql_docs = generate_docs_str(content, None)?;
225227
vec![sql_docs]
226-
},
227-
SqlFileDocSource::FromStringsWithPaths(strings_paths ) => generate_docs_from_strs_with_paths(strings_paths)?,
228+
}
229+
SqlFileDocSource::FromStringsWithPaths(strings_paths) => {
230+
generate_docs_from_strs_with_paths(strings_paths)?
231+
}
228232
SqlFileDocSource::Files(files) => generate_docs_from_files(files)?,
229233
};
230234
let num_of_tables = docs.iter().map(super::docs::SqlFileDoc::number_of_tables).sum();
@@ -314,9 +318,11 @@ fn generate_docs_str(content: &str, path: Option<PathBuf>) -> Result<SqlFileDoc,
314318
Ok(docs)
315319
}
316320

317-
fn generate_docs_from_strs_with_paths(strings_with_paths: &[(String, PathBuf)]) -> Result<Vec<SqlFileDoc>, DocError> {
321+
fn generate_docs_from_strs_with_paths(
322+
strings_with_paths: &[(String, PathBuf)],
323+
) -> Result<Vec<SqlFileDoc>, DocError> {
318324
let mut docs = Vec::new();
319-
for (content,path) in strings_with_paths {
325+
for (content, path) in strings_with_paths {
320326
docs.push(generate_docs_str(content, Some(path.to_owned()))?);
321327
}
322328

@@ -837,4 +843,100 @@ mod tests {
837843
assert_eq!(t.schema(), Some("public"));
838844
Ok(())
839845
}
846+
#[test]
847+
fn test_generate_docs_from_strs_with_paths_builds_tables_and_stamps_paths()
848+
-> Result<(), Box<dyn std::error::Error>> {
849+
// Two simple SQL strings with distinct paths
850+
let sql1 = r#"
851+
-- Users table
852+
CREATE TABLE users (
853+
-- id
854+
id INTEGER PRIMARY KEY
855+
);
856+
"#;
857+
858+
let sql2 = r#"
859+
/* Posts table */
860+
CREATE TABLE posts (
861+
/* primary key */
862+
id INTEGER PRIMARY KEY
863+
);
864+
"#;
865+
866+
let p1 = PathBuf::from("a/one.sql");
867+
let p2 = PathBuf::from("b/two.sql");
868+
869+
// NOTE: builder expects owned String for sql and a PathBuf
870+
let inputs: Vec<(String, PathBuf)> =
871+
vec![(sql1.to_owned(), p1.clone()), (sql2.to_owned(), p2.clone())];
872+
873+
// Build via the new builder arm
874+
let doc = SqlDoc::builder_from_strs_with_paths(&inputs).build()?;
875+
876+
// We should have 2 tables total
877+
assert_eq!(doc.tables().len(), 2);
878+
879+
// Verify table names exist
880+
let users = doc.table("users", None)?;
881+
let posts = doc.table("posts", None)?;
882+
883+
// Verify each table got the correct stamped path
884+
assert_eq!(users.path(), Some(p1.as_path()));
885+
assert_eq!(posts.path(), Some(p2.as_path()));
886+
887+
Ok(())
888+
}
889+
890+
#[test]
891+
fn test_builder_from_strs_with_paths_is_used_in_build_match_arm()
892+
-> Result<(), Box<dyn std::error::Error>> {
893+
let sql_a = "CREATE TABLE alpha (id INTEGER);";
894+
let sql_b = "CREATE TABLE beta (id INTEGER);";
895+
let path_a = PathBuf::from("alpha.sql");
896+
let path_b = PathBuf::from("beta.sql");
897+
898+
let inputs = vec![(sql_a.to_owned(), path_a.clone()), (sql_b.to_owned(), path_b.clone())];
899+
900+
let built = SqlDoc::builder_from_strs_with_paths(&inputs).build()?;
901+
902+
let names: Vec<&str> = built.tables().iter().map(|t| t.name()).collect();
903+
assert_eq!(names, vec!["alpha", "beta"]);
904+
905+
assert_eq!(built.table("alpha", None)?.path(), Some(path_a.as_path()));
906+
assert_eq!(built.table("beta", None)?.path(), Some(path_b.as_path()));
907+
908+
Ok(())
909+
}
910+
911+
#[test]
912+
fn test_builder_from_str_no_path_has_none_path() -> Result<(), Box<dyn std::error::Error>> {
913+
let sql = "CREATE TABLE t (id INTEGER);";
914+
let built = SqlDoc::builder_from_str(sql).build()?;
915+
916+
let t = built.table("t", None)?;
917+
assert_eq!(t.path(), None);
918+
919+
Ok(())
920+
}
921+
#[test]
922+
fn test_table_with_schema_not_found_uses_no_schema_provided_message() {
923+
use crate::{SqlDoc, docs::TableDoc, error::DocError};
924+
925+
let sql_doc = SqlDoc::new(vec![
926+
TableDoc::new(Some("analytics".to_owned()), "events".to_owned(), None, vec![], None),
927+
TableDoc::new(Some("public".to_owned()), "events".to_owned(), None, vec![], None),
928+
]);
929+
930+
match sql_doc.table("events", None) {
931+
Err(DocError::TableWithSchemaNotFound { name, schema }) => {
932+
assert_eq!(name, "events");
933+
assert_eq!(schema, "No schema provided");
934+
}
935+
Err(e) => panic!(
936+
"expected TableWithSchemaNotFound with 'No schema provided', got: {e:?}"
937+
),
938+
Ok(_) => panic!("expected error, got Ok"),
939+
}
940+
}
941+
840942
}

0 commit comments

Comments
 (0)