Skip to content

Commit 1ed25b4

Browse files
committed
Implemented SqlDoc methods and error handling
1 parent 6504b8a commit 1ed25b4

4 files changed

Lines changed: 120 additions & 13 deletions

File tree

src/docs.rs

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Module for parsing sql and comments and returning `table` and `column`
22
//! information, including comments
3+
use core::fmt;
4+
35
use sqlparser::ast::{Ident, ObjectName, ObjectNamePart, Spanned, Statement};
46

57
use crate::{ast::ParsedSqlFile, comments::Comments, error::DocError};
@@ -32,8 +34,20 @@ impl ColumnDoc {
3234
/// Getter for the field `doc`
3335
#[must_use]
3436
#[allow(clippy::missing_const_for_fn)]
35-
pub fn doc(&self) -> &Option<String> {
36-
&self.doc
37+
pub fn doc(&self) -> Option<&str> {
38+
self.doc.as_deref()
39+
}
40+
}
41+
42+
impl fmt::Display for ColumnDoc {
43+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44+
writeln!(f, "Column Name: {}", self.name())?;
45+
if let Some(c) = self.doc() {
46+
writeln!(f, "Column Doc: {c}")?;
47+
} else {
48+
writeln!(f, "No Column Doc Found")?;
49+
}
50+
Ok(())
3751
}
3852
}
3953

@@ -66,6 +80,12 @@ impl TableDoc {
6680
Self { schema, name, doc, columns }
6781
}
6882

83+
/// Getter for the `Schema` of the table (if there is one)
84+
#[must_use]
85+
pub fn schema(&self) -> Option<&str> {
86+
self.schema.as_deref()
87+
}
88+
6989
/// Getter for the `name` field
7090
#[must_use]
7191
#[allow(clippy::missing_const_for_fn)]
@@ -76,8 +96,8 @@ impl TableDoc {
7696
/// Getter for the `doc` field
7797
#[must_use]
7898
#[allow(clippy::missing_const_for_fn)]
79-
pub fn doc(&self) -> &Option<String> {
80-
&self.doc
99+
pub fn doc(&self) -> Option<&str> {
100+
self.doc.as_deref()
81101
}
82102

83103
/// Getter for the `columns` field
@@ -88,6 +108,30 @@ impl TableDoc {
88108
}
89109
}
90110

111+
impl fmt::Display for TableDoc {
112+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113+
if let Some(s) = self.schema() {
114+
writeln!(f, "Table Schema: {s}")?;
115+
} else {
116+
writeln!(f, "No Table Schema")?;
117+
}
118+
119+
writeln!(f, "Table Name: {}", self.name())?;
120+
121+
if let Some(d) = self.doc() {
122+
writeln!(f, "Table Doc: {d}")?;
123+
} else {
124+
writeln!(f, "No Table Doc")?;
125+
}
126+
127+
writeln!(f, "Table Column Docs: ")?;
128+
for col in self.columns() {
129+
writeln!(f, " {col}")?;
130+
}
131+
Ok(())
132+
}
133+
}
134+
91135
/// Structure for containing the docs for every `Table` in an `.sql` file as a
92136
/// `Vec` of [`TableDoc`]
93137
#[derive(Clone, Debug, Eq, PartialEq)]

src/error.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//! Module for managing Document Errors as [`DocError`]
2-
use crate::comments::CommentError;
2+
use crate::{comments::CommentError, docs::TableDoc};
33
use core::fmt;
44
use sqlparser::parser::ParserError;
55
use std::{error, fmt::Debug};
@@ -21,6 +21,16 @@ pub enum DocError {
2121
/// The column number for the invalid [`sqlparser::ast::ObjectName`]
2222
column: u64,
2323
},
24+
/// Table not found when searching [`crate::SqlDoc`]
25+
TableNotFound {
26+
/// The name of the table that was not found
27+
name: String,
28+
},
29+
/// Duplicate tables with same name were found when searching [`crate::SqlDoc`]
30+
DuplicateTablesFound {
31+
/// `Vec` of the [`TableDoc`] for each duplicate table found
32+
tables: Vec<TableDoc>
33+
}
2434
}
2535

2636
impl fmt::Display for DocError {
@@ -33,7 +43,16 @@ impl fmt::Display for DocError {
3343
Self::SqlParserError(parser_error) => write!(f, "SQL parse error {parser_error}"),
3444
Self::InvalidObjectName { message, line, column } => {
3545
write!(f, "{message} at line {line}, column {column}")
46+
},
47+
Self::TableNotFound{name} => write!(f, "Table not found in SqlDoc: {name}"),
48+
Self::DuplicateTablesFound { tables } => {
49+
writeln!(f, "Duplicate tables found:")?;
50+
for t in tables {
51+
writeln!(f, "{t}")?;
52+
}
53+
Ok(())
3654
}
55+
3756
}
3857
}
3958
}
@@ -44,7 +63,7 @@ impl error::Error for DocError {
4463
Self::FileReadError(e) => Some(e),
4564
Self::CommentError(e) => Some(e),
4665
Self::SqlParserError(e) => Some(e),
47-
Self::InvalidObjectName { .. } => None,
66+
Self::InvalidObjectName { .. } | Self::TableNotFound { .. } | Self::DuplicateTablesFound { .. } => None,
4867
}
4968
}
5069
}

src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ mod tests {
110110
assert_eq!(parsed_doc.tables()[i].name(), table_names[i]);
111111
let parsed_doc_table_doc = parsed_doc.tables()[i]
112112
.doc()
113-
.as_ref()
114113
.map_or_else(|| panic!("unable to find SqlFileDoc table doc"), |val| val);
115114
assert_eq!(parsed_doc_table_doc, table_comments[i]);
116115
}
@@ -124,7 +123,6 @@ mod tests {
124123
assert_eq!(column.name(), user_columns[i]);
125124
let column_doc = column
126125
.doc()
127-
.as_ref()
128126
.map_or_else(|| panic!("unable to find column doc value"), |val| val);
129127
assert_eq!(column_doc, user_columns_comments[i]);
130128
}

src/sql_doc.rs

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,8 @@
33
use std::path::{Path, PathBuf};
44

55
use crate::{
6-
ast::ParsedSqlFileSet,
7-
comments::Comments,
8-
docs::{SqlFileDoc, TableDoc, ColumnDoc},
6+
docs::{SqlFileDoc, TableDoc},
97
error::DocError,
10-
files::SqlFileSet,
118
};
129

1310
/// Structure for Sql Documentation, built from [`TableDoc`] and
@@ -34,8 +31,57 @@ enum SqlFileDocSource {
3431
}
3532

3633
impl SqlDoc {
34+
/// Method for generating builder from a directory.
35+
pub fn from_dir<P: AsRef<Path>>(root: P) -> SqlDocBuilder {
36+
SqlDocBuilder { source: SqlFileDocSource::Dir(root.as_ref().to_path_buf()), deny: Vec::new() }
37+
}
38+
/// Method for generating builder from a [`Path`] of a single file
39+
pub fn from_path<P: AsRef<Path>>(path: P) -> SqlDocBuilder {
40+
SqlDocBuilder { source: SqlFileDocSource::File(path.as_ref().to_path_buf()), deny: Vec::new() }
41+
}
3742

38-
43+
/// Method for finding a specific [`TableDoc`] by `name`
44+
///
45+
/// # Parameters
46+
/// - the table `name` as a [`str`]
47+
///
48+
/// # Errors
49+
/// - Will return [`DocError::TableNotFound`] if the expected table is not found
50+
/// - Will return [`DocError::DuplicateTablesFound`] if more than one table is found
51+
pub fn table(&self, table: &str) -> Result<&TableDoc, DocError> {
52+
let matches = self.tables.iter().filter(|table_doc| table_doc.name() == table).collect::<Vec<&TableDoc>>();
53+
match matches.as_slice() {
54+
[] => Err(DocError::TableNotFound {
55+
name: table.to_string(),
56+
}),
57+
[only] => Ok(*only),
58+
_ => Err(DocError::DuplicateTablesFound {
59+
tables: matches.into_iter().cloned().collect(),
60+
}),
61+
}
62+
}
63+
64+
/// Method for finding a specific [`TableDoc`] from `schema` and table `name`
65+
///
66+
/// # Parameters
67+
/// - the table's `schema` as a [`str`]
68+
/// - the table's `name` as a [`str`]
69+
///
70+
/// # Errors
71+
/// - Will return [`DocError::TableNotFound`] if the expected table is not found
72+
/// - Will return [`DocError::DuplicateTablesFound`] if more than one table is found
73+
pub fn table_with_schema(&self, schema: &str, name: &str) -> Result<&TableDoc, DocError> {
74+
let matches = self.tables.iter().filter(|table_doc| table_doc.name() == name && table_doc.schema() == Some(schema)).collect::<Vec<&TableDoc>>();
75+
match matches.as_slice() {
76+
[] => Err(DocError::TableNotFound {
77+
name: name.to_string(),
78+
}),
79+
[only] => Ok(*only),
80+
_ => Err(DocError::DuplicateTablesFound {
81+
tables: matches.into_iter().cloned().collect(),
82+
}),
83+
}
84+
}
3985
}
4086

4187
impl SqlDocBuilder {

0 commit comments

Comments
 (0)