Skip to content

Commit caa7155

Browse files
committed
Comment Structure Defined
1 parent d80a65b commit caa7155

5 files changed

Lines changed: 214 additions & 15 deletions

File tree

src/ast.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//! Module for parsing the SQL and then using the resulting AST to walk back and
2+
//! check for comments
3+
use std::path::Path;
4+
5+
use sqlparser::{
6+
ast::Statement,
7+
dialect::GenericDialect,
8+
parser::{Parser, ParserError},
9+
};
10+
11+
use crate::files::{SqlFile, SqlFileSet};
12+
13+
/// A single SQL file plus all [`Statement`].
14+
pub struct ParsedSqlFile {
15+
file: SqlFile,
16+
statements: Vec<Statement>,
17+
}
18+
19+
impl ParsedSqlFile {
20+
/// Parses all statements from the specified sql file
21+
///
22+
/// # Parameters
23+
/// - `file` is the [`SqlFile`] that will be parsed
24+
///
25+
/// # Errors
26+
/// - [`ParserError`] is returned for any errors parsing
27+
pub fn parse(file: SqlFile) -> Result<Self, ParserError> {
28+
let dialect = GenericDialect {};
29+
let statements = Parser::parse_sql(&dialect, file.content())?;
30+
Ok(Self { file, statements })
31+
}
32+
33+
/// Getter method for returning the current object's file's path
34+
#[must_use]
35+
pub fn path(&self) -> &Path {
36+
self.file.path()
37+
}
38+
39+
/// Getter method for returning the vector of all statements [`Statement`]
40+
#[must_use]
41+
pub fn statements(&self) -> &[Statement] {
42+
&self.statements
43+
}
44+
}
45+
46+
/// Struct to contain the vector of parsed SQL files
47+
pub struct ParsedSqlFileSet {
48+
files: Vec<ParsedSqlFile>,
49+
}
50+
51+
impl ParsedSqlFileSet {
52+
/// Method that parses all members in a [`SqlFileSet`]
53+
///
54+
/// # Parameters
55+
/// - `set` the set of [`SqlFileSet`]
56+
///
57+
/// # Errors
58+
/// - [`ParserError`] is returned for any errors parsing
59+
pub fn parse_all(set: SqlFileSet) -> Result<Self, ParserError> {
60+
let files = set.into_iter().map(ParsedSqlFile::parse).collect::<Result<Vec<_>, _>>()?;
61+
62+
Ok(Self { files })
63+
}
64+
65+
/// Getter method for returning the vector of all [`ParsedSqlFile`]
66+
#[must_use]
67+
pub fn files(&self) -> &[ParsedSqlFile] {
68+
&self.files
69+
}
70+
}

src/comments.rs

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
//! Module for crawling the SQL documents based on the parser and
2+
//! parsing/extracting the leading comments.
3+
//!
4+
//! *leading comment* a comment that
5+
//! precedes an SQL Statement.
6+
7+
/// Structure for holding a location in the file. Assumes file is first split by
8+
/// lines and then split by characters (column)
9+
pub struct Location {
10+
line: u64,
11+
column: u64,
12+
}
13+
14+
impl Location {
15+
/// Method for instantiating a new [`Location`]
16+
///
17+
/// # Parameters
18+
/// - line: the [`u64`] value of the line location
19+
/// - column: the [`u64`] value of the column location
20+
#[must_use]
21+
pub const fn new(line: u64, column: u64) -> Self {
22+
Self { line, column }
23+
}
24+
25+
/// Getter method for getting the line value
26+
#[must_use]
27+
pub const fn line(&self) -> u64 {
28+
self.line
29+
}
30+
31+
/// Getter method for getting the column value
32+
#[must_use]
33+
pub const fn column(&self) -> u64 {
34+
self.column
35+
}
36+
}
37+
38+
/// A structure for holding the span of comments found
39+
pub struct CommentSpan {
40+
start: Location,
41+
end: Location,
42+
}
43+
44+
impl CommentSpan {
45+
/// Method for creating a new instance of the [`CommentSpan`] for a
46+
/// comment's span
47+
///
48+
/// # Parameters
49+
/// - the [`Location`] where the comment starts in the file
50+
/// - the [`Location`] where the comment ends in the file
51+
#[must_use]
52+
pub const fn new(start: Location, end: Location) -> Self {
53+
Self { start, end }
54+
}
55+
56+
/// Getter for the start location of a [`CommentSpan`]
57+
#[must_use]
58+
pub const fn start(&self) -> &Location {
59+
&self.start
60+
}
61+
62+
/// Getter for the end location of a [`CommentSpan`]
63+
#[must_use]
64+
pub const fn end(&self) -> &Location {
65+
&self.end
66+
}
67+
}
68+
69+
/// Structure that holds the comment along with its location in the file
70+
pub struct Comment {
71+
comment: String,
72+
span: CommentSpan,
73+
}
74+
75+
impl Comment {
76+
/// Method for creating a new [`Comment`] from the comment [`String`] and
77+
/// the [`CommentSpan`]
78+
///
79+
/// # Parameters
80+
/// - the comment as a [`String`]
81+
/// - the span of the comment as a [`CommentSpan`]
82+
#[must_use]
83+
pub const fn new(comment: String, span: CommentSpan) -> Self {
84+
Self { comment, span }
85+
}
86+
87+
/// Getter method for retrieving the comment content
88+
#[must_use]
89+
pub fn comment(&self) -> &str {
90+
&self.comment
91+
}
92+
93+
/// Getter method for retrieving the [`CommentSpan`] of the comment
94+
#[must_use]
95+
pub const fn span(&self) -> &CommentSpan {
96+
&self.span
97+
}
98+
}
99+
100+
/// Structure for holding all comments found in the document
101+
pub struct Comments {
102+
comments: Vec<Comment>,
103+
}
104+
105+
impl Comments {
106+
/// Method for generating a new [`Comments`] struct, which sorts comments
107+
/// based on their starting span location
108+
///
109+
/// # Parameters
110+
/// - `comments`: mutable [`Vec<Comment>`] that will be sorted by span start
111+
#[must_use]
112+
pub fn new(mut comments: Vec<Comment>) -> Self {
113+
// Always keep comments ordered by their span
114+
comments.sort_by(|a, b| {
115+
let a_start = a.span().start();
116+
let b_start = b.span().start();
117+
118+
a_start
119+
.line()
120+
.cmp(&b_start.line())
121+
.then_with(|| a_start.column().cmp(&b_start.column()))
122+
});
123+
124+
Self { comments }
125+
}
126+
127+
/// Getter method for retrieving the Vec of [`Comment`]
128+
#[must_use]
129+
pub fn comments(&self) -> &[Comment] {
130+
&self.comments
131+
}
132+
}

src/files.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,15 @@ impl SqlFileSet {
157157
}
158158
}
159159

160+
impl IntoIterator for SqlFileSet {
161+
type IntoIter = std::vec::IntoIter<SqlFile>;
162+
type Item = SqlFile;
163+
164+
fn into_iter(self) -> Self::IntoIter {
165+
self.files_contents.into_iter()
166+
}
167+
}
168+
160169
#[cfg(test)]
161170
mod tests {
162171
use std::{env, fs};

src/main.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ use std::{error::Error, path::Path};
33

44
use sqlparser::{dialect::GenericDialect, parser::Parser};
55

6+
pub mod ast;
7+
pub mod comments;
68
pub mod files;
7-
pub mod parser;
89
fn main() -> Result<(), Box<dyn Error>> {
910
let path: &Path = Path::new("/home/alex/Projects/sql-docs/sql_files/");
1011

@@ -13,7 +14,7 @@ fn main() -> Result<(), Box<dyn Error>> {
1314
for sql in sql_file_set.iter() {
1415
let dialect = GenericDialect {}; // or AnsiDialect, or your own dialect ...
1516

16-
let ast = Parser::parse_sql(&dialect, sql.content()).unwrap();
17+
let ast = Parser::parse_sql(&dialect, sql.content())?;
1718

1819
println!("AST: {ast:?}");
1920
}

src/parser.rs

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)