Skip to content

Commit f6bf815

Browse files
committed
implemented column() to return a ColumnDoc for a specified column
1 parent fa4c074 commit f6bf815

4 files changed

Lines changed: 116 additions & 19 deletions

File tree

Cargo.lock

Lines changed: 15 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "sql_docs"
3-
version = "1.0.4"
3+
version = "1.0.5"
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"
@@ -25,6 +25,7 @@ fuzzing = []
2525
sqlparser = "0.60.0"
2626

2727

28+
2829
[lints.rust]
2930
missing_docs = "forbid"
3031
unreachable_patterns = "forbid"

src/docs.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,28 @@ impl TableDoc {
125125
&mut self.columns
126126
}
127127

128+
/// Method for finding a specific [`ColumnDoc`] from `schema` and table `name`
129+
///
130+
/// # Parameters
131+
/// - the column's `name` as a [`str`]
132+
///
133+
/// # Errors
134+
/// - Will return [`DocError::ColumnNotFound`] if the expected table is not found
135+
pub fn column(&self, column: &str) -> Result<&ColumnDoc, DocError> {
136+
let matches = self
137+
.columns
138+
.iter()
139+
.filter(|col_doc| col_doc.name() == column)
140+
.collect::<Vec<&ColumnDoc>>();
141+
match matches.as_slice() {
142+
[] => Err(DocError::ColumnNotFound { name: column.to_owned() }),
143+
[only] => Ok(*only),
144+
_ => Err(DocError::DuplicateColumnsFound {
145+
columns: matches.into_iter().cloned().collect(),
146+
}),
147+
}
148+
}
149+
128150
/// Getter method for retrieving the table's [`Path`]
129151
#[must_use]
130152
pub fn path(&self) -> Option<&Path> {
@@ -851,7 +873,7 @@ CREATE TABLE posts (
851873
assert_eq!(got, expected);
852874
}
853875
#[test]
854-
fn table_doc_path_getter_returns_expected_value() {
876+
fn test_table_doc_path_getter_returns_expected_value() {
855877
let mut table = TableDoc::new(None, "users".to_owned(), None, Vec::new(), None);
856878
assert_eq!(table.path(), None);
857879
let pb = PathBuf::from("some/dir/file.sql");
@@ -861,4 +883,25 @@ CREATE TABLE posts (
861883
table.set_path(no_path);
862884
assert_eq!(table.path(), None);
863885
}
886+
887+
#[test]
888+
fn test_table_doc_column() {
889+
let table = TableDoc::new(
890+
None,
891+
"users".to_owned(),
892+
None,
893+
vec![
894+
ColumnDoc::new("id".to_owned(), None),
895+
ColumnDoc::new("username".to_owned(), None),
896+
],
897+
None,
898+
);
899+
900+
let col = table.column("id").unwrap_or_else(|_| panic!("Column 'id' should exist"));
901+
assert_eq!(col.name(), "id");
902+
903+
let missing = table.column("nope");
904+
assert!(missing.is_err());
905+
assert!(matches!(missing, Err(DocError::ColumnNotFound { name }) if name == "nope"));
906+
}
864907
}

src/error.rs

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
//! Error types returned by this crate’s public APIs.
22
3-
use crate::{comments::CommentError, docs::TableDoc};
3+
use crate::{
4+
comments::CommentError,
5+
docs::{ColumnDoc, TableDoc},
6+
};
47
use core::fmt;
58
use sqlparser::parser::ParserError;
69
use std::{error, fmt::Debug};
@@ -29,11 +32,21 @@ pub enum DocError {
2932
/// The name of the table that was not found
3033
name: String,
3134
},
35+
/// Column not found when searching [`crate::docs::TableDoc`]
36+
ColumnNotFound {
37+
/// The name of the column not found
38+
name: String,
39+
},
3240
/// Duplicate tables with same name were found when searching [`crate::SqlDoc`]
3341
DuplicateTablesFound {
3442
/// `Vec` of the [`TableDoc`] for each duplicate table found
3543
tables: Vec<TableDoc>,
3644
},
45+
/// Duplicate columns with same name were found when searching a single [`TableDoc`]
46+
DuplicateColumnsFound {
47+
/// `Vec` of the [`crate::docs::ColumnDoc`] for each duplicate table found
48+
columns: Vec<ColumnDoc>,
49+
},
3750
}
3851

3952
impl fmt::Display for DocError {
@@ -48,13 +61,21 @@ impl fmt::Display for DocError {
4861
write!(f, "{message} at line {line}, column {column}")
4962
}
5063
Self::TableNotFound { name } => write!(f, "Table not found in SqlDoc: {name}"),
64+
Self::ColumnNotFound { name } => write!(f, "Column not found in TableDoc: {name}"),
5165
Self::DuplicateTablesFound { tables } => {
5266
writeln!(f, "Duplicate tables found:")?;
5367
for t in tables {
5468
writeln!(f, "{t}")?;
5569
}
5670
Ok(())
5771
}
72+
Self::DuplicateColumnsFound { columns } => {
73+
writeln!(f, "Duplicate columns found:")?;
74+
for t in columns {
75+
writeln!(f, "{t}")?;
76+
}
77+
Ok(())
78+
}
5879
}
5980
}
6081
}
@@ -67,7 +88,9 @@ impl error::Error for DocError {
6788
Self::SqlParserError(e) => Some(e),
6889
Self::InvalidObjectName { .. }
6990
| Self::TableNotFound { .. }
70-
| Self::DuplicateTablesFound { .. } => None,
91+
| Self::ColumnNotFound { .. }
92+
| Self::DuplicateTablesFound { .. }
93+
| Self::DuplicateColumnsFound { .. } => None,
7194
}
7295
}
7396
}
@@ -222,4 +245,34 @@ mod tests {
222245
let dup = DocError::DuplicateTablesFound { tables: vec![] };
223246
assert!(dup.source().is_none());
224247
}
248+
249+
#[test]
250+
fn test_doc_error_display_column_not_found() {
251+
let e = DocError::ColumnNotFound { name: "id".to_string() };
252+
assert_eq!(e.to_string(), "Column not found in TableDoc: id");
253+
}
254+
255+
#[test]
256+
fn test_doc_error_display_duplicate_columns_found() {
257+
use crate::docs::ColumnDoc;
258+
259+
let c1 = ColumnDoc::new("dup_col".to_string(), None);
260+
let c2 = ColumnDoc::new("dup_col".to_string(), None);
261+
let e = DocError::DuplicateColumnsFound { columns: vec![c1, c2] };
262+
263+
let s = e.to_string();
264+
assert!(s.contains("Duplicate columns found:"), "output was: {s}");
265+
assert!(s.contains("dup_col"), "output was: {s}");
266+
}
267+
268+
#[test]
269+
fn test_doc_error_source_none_for_column_variants() {
270+
use std::error::Error as _;
271+
272+
let not_found = DocError::ColumnNotFound { name: "x".to_string() };
273+
assert!(not_found.source().is_none());
274+
275+
let dup = DocError::DuplicateColumnsFound { columns: vec![] };
276+
assert!(dup.source().is_none());
277+
}
225278
}

0 commit comments

Comments
 (0)