|
2 | 2 |
|
3 | 3 | use std::{ |
4 | 4 | path::{Path, PathBuf}, |
5 | | - str::FromStr, vec, |
| 5 | + str::FromStr, |
| 6 | + vec, |
6 | 7 | }; |
7 | 8 |
|
8 | 9 | use crate::{ |
@@ -49,7 +50,7 @@ enum SqlFileDocSource<'a> { |
49 | 50 | File(PathBuf), |
50 | 51 | Files(Vec<PathBuf>), |
51 | 52 | FromString(&'a str), |
52 | | - FromStringsWithPaths(&'a[(String, PathBuf)]) |
| 53 | + FromStringsWithPaths(&'a [(String, PathBuf)]), |
53 | 54 | } |
54 | 55 |
|
55 | 56 | impl SqlDoc { |
@@ -100,14 +101,15 @@ impl SqlDoc { |
100 | 101 |
|
101 | 102 | /// Creates a builder from a vec of tuples containing the `sql` as [`String`] and the path as [`PathBuf`] |
102 | 103 | #[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<'_> { |
104 | 107 | SqlDocBuilder { |
105 | 108 | source: SqlFileDocSource::FromStringsWithPaths(string_with_path), |
106 | 109 | deny: Vec::new(), |
107 | | - multiline_flat: MultiFlatten::NoFlat |
| 110 | + multiline_flat: MultiFlatten::NoFlat, |
108 | 111 | } |
109 | 112 | } |
110 | | - |
111 | 113 |
|
112 | 114 | /// Method for finding a specific [`TableDoc`] by `name` |
113 | 115 | /// |
@@ -223,8 +225,10 @@ impl SqlDocBuilder<'_> { |
223 | 225 | SqlFileDocSource::FromString(content) => { |
224 | 226 | let sql_docs = generate_docs_str(content, None)?; |
225 | 227 | 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 | + } |
228 | 232 | SqlFileDocSource::Files(files) => generate_docs_from_files(files)?, |
229 | 233 | }; |
230 | 234 | 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, |
314 | 318 | Ok(docs) |
315 | 319 | } |
316 | 320 |
|
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> { |
318 | 324 | let mut docs = Vec::new(); |
319 | | - for (content,path) in strings_with_paths { |
| 325 | + for (content, path) in strings_with_paths { |
320 | 326 | docs.push(generate_docs_str(content, Some(path.to_owned()))?); |
321 | 327 | } |
322 | 328 |
|
@@ -837,4 +843,100 @@ mod tests { |
837 | 843 | assert_eq!(t.schema(), Some("public")); |
838 | 844 | Ok(()) |
839 | 845 | } |
| 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 | + |
840 | 942 | } |
0 commit comments