Skip to content

Commit 5ecf633

Browse files
authored
Add dialect_from_str and improve Dialect documentation (#848)
* Add `dialect_from_str` and improve `Dialect` documentation * cleanup * fix compilation with nostd
1 parent d8af925 commit 5ecf633

File tree

4 files changed

+99
-8
lines changed

4 files changed

+99
-8
lines changed

src/dialect/mod.rs

+84-2
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,47 @@ pub use self::sqlite::SQLiteDialect;
4242
pub use crate::keywords;
4343
use crate::parser::{Parser, ParserError};
4444

45-
/// `dialect_of!(parser is SQLiteDialect | GenericDialect)` evaluates
46-
/// to `true` if `parser.dialect` is one of the `Dialect`s specified.
45+
#[cfg(not(feature = "std"))]
46+
use alloc::boxed::Box;
47+
48+
/// Convenience check if a [`Parser`] uses a certain dialect.
49+
///
50+
/// `dialect_of!(parser Is SQLiteDialect | GenericDialect)` evaluates
51+
/// to `true` if `parser.dialect` is one of the [`Dialect`]s specified.
4752
macro_rules! dialect_of {
4853
( $parsed_dialect: ident is $($dialect_type: ty)|+ ) => {
4954
($($parsed_dialect.dialect.is::<$dialect_type>())||+)
5055
};
5156
}
5257

58+
/// Encapsulates the differences between SQL implementations.
59+
///
60+
/// # SQL Dialects
61+
/// SQL implementations deviatiate from one another, either due to
62+
/// custom extensions or various historical reasons. This trait
63+
/// encapsulates the parsing differences between dialects.
64+
///
65+
/// # Examples
66+
/// Most users create a [`Dialect`] directly, as shown on the [module
67+
/// level documentation]:
68+
///
69+
/// ```
70+
/// # use sqlparser::dialect::AnsiDialect;
71+
/// let dialect = AnsiDialect {};
72+
/// ```
73+
///
74+
/// It is also possible to dynamically create a [`Dialect`] from its
75+
/// name. For example:
76+
///
77+
/// ```
78+
/// # use sqlparser::dialect::{AnsiDialect, dialect_from_str};
79+
/// let dialect = dialect_from_str("ansi").unwrap();
80+
///
81+
/// // Parsed dialect is an instance of `AnsiDialect`:
82+
/// assert!(dialect.is::<AnsiDialect>());
83+
/// ```
84+
///
85+
/// [module level documentation]: crate
5386
pub trait Dialect: Debug + Any {
5487
/// Determine if a character starts a quoted identifier. The default
5588
/// implementation, accepting "double quoted" ids is both ANSI-compliant
@@ -113,6 +146,27 @@ impl dyn Dialect {
113146
}
114147
}
115148

149+
/// Returns the built in [`Dialect`] corresponding to `dialect_name`.
150+
///
151+
/// See [`Dialect`] documentation for an example.
152+
pub fn dialect_from_str(dialect_name: impl AsRef<str>) -> Option<Box<dyn Dialect>> {
153+
let dialect_name = dialect_name.as_ref();
154+
match dialect_name.to_lowercase().as_str() {
155+
"generic" => Some(Box::new(GenericDialect)),
156+
"mysql" => Some(Box::new(MySqlDialect {})),
157+
"postgresql" | "postgres" => Some(Box::new(PostgreSqlDialect {})),
158+
"hive" => Some(Box::new(HiveDialect {})),
159+
"sqlite" => Some(Box::new(SQLiteDialect {})),
160+
"snowflake" => Some(Box::new(SnowflakeDialect)),
161+
"redshift" => Some(Box::new(RedshiftSqlDialect {})),
162+
"mssql" => Some(Box::new(MsSqlDialect {})),
163+
"clickhouse" => Some(Box::new(ClickHouseDialect {})),
164+
"bigquery" => Some(Box::new(BigQueryDialect)),
165+
"ansi" => Some(Box::new(AnsiDialect {})),
166+
_ => None,
167+
}
168+
}
169+
116170
#[cfg(test)]
117171
mod tests {
118172
use super::ansi::AnsiDialect;
@@ -141,4 +195,32 @@ mod tests {
141195
assert!(dialect_of!(ansi_holder is GenericDialect | AnsiDialect));
142196
assert!(!dialect_of!(ansi_holder is GenericDialect | MsSqlDialect));
143197
}
198+
199+
#[test]
200+
fn test_dialect_from_str() {
201+
assert!(parse_dialect("generic").is::<GenericDialect>());
202+
assert!(parse_dialect("mysql").is::<MySqlDialect>());
203+
assert!(parse_dialect("MySql").is::<MySqlDialect>());
204+
assert!(parse_dialect("postgresql").is::<PostgreSqlDialect>());
205+
assert!(parse_dialect("postgres").is::<PostgreSqlDialect>());
206+
assert!(parse_dialect("hive").is::<HiveDialect>());
207+
assert!(parse_dialect("sqlite").is::<SQLiteDialect>());
208+
assert!(parse_dialect("snowflake").is::<SnowflakeDialect>());
209+
assert!(parse_dialect("SnowFlake").is::<SnowflakeDialect>());
210+
assert!(parse_dialect("MsSql").is::<MsSqlDialect>());
211+
assert!(parse_dialect("clickhouse").is::<ClickHouseDialect>());
212+
assert!(parse_dialect("ClickHouse").is::<ClickHouseDialect>());
213+
assert!(parse_dialect("bigquery").is::<BigQueryDialect>());
214+
assert!(parse_dialect("BigQuery").is::<BigQueryDialect>());
215+
assert!(parse_dialect("ansi").is::<AnsiDialect>());
216+
assert!(parse_dialect("ANSI").is::<AnsiDialect>());
217+
218+
// error cases
219+
assert!(dialect_from_str("Unknown").is_none());
220+
assert!(dialect_from_str("").is_none());
221+
}
222+
223+
fn parse_dialect(v: &str) -> Box<dyn Dialect> {
224+
dialect_from_str(v).unwrap()
225+
}
144226
}

src/dialect/mssql.rs

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
use crate::dialect::Dialect;
1414

15+
// [Microsoft SQL Server](https://www.microsoft.com/en-us/sql-server/) dialect
1516
#[derive(Debug)]
1617
pub struct MsSqlDialect {}
1718

src/dialect/mysql.rs

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
use crate::dialect::Dialect;
1414

15+
/// [MySQL](https://www.mysql.com/)
1516
#[derive(Debug)]
1617
pub struct MySqlDialect {}
1718

src/lib.rs

+13-6
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,18 @@
1010
// See the License for the specific language governing permissions and
1111
// limitations under the License.
1212

13-
//! SQL Parser for Rust
13+
//! # SQL Parser for Rust
1414
//!
1515
//! This crate provides an ANSI:SQL 2011 lexer and parser that can parse SQL
16-
//! into an Abstract Syntax Tree (AST). See the [sqlparser crates.io page]
16+
//! into an Abstract Syntax Tree ([`AST`]). See the [sqlparser crates.io page]
1717
//! for more information.
1818
//!
19-
//! See [`Parser::parse_sql`](crate::parser::Parser::parse_sql) and
20-
//! [`Parser::new`](crate::parser::Parser::new) for the Parsing API
21-
//! and the [`ast`](crate::ast) crate for the AST structure.
19+
//! For more information:
20+
//! 1. [`Parser::parse_sql`] and [`Parser::new`] for the Parsing API
21+
//! 2. [`ast`] for the AST structure
22+
//! 3. [`Dialect`] for supported SQL dialects
2223
//!
23-
//! Example:
24+
//! # Example
2425
//!
2526
//! ```
2627
//! use sqlparser::dialect::GenericDialect;
@@ -37,7 +38,13 @@
3738
//!
3839
//! println!("AST: {:?}", ast);
3940
//! ```
41+
//!
4042
//! [sqlparser crates.io page]: https://crates.io/crates/sqlparser
43+
//! [`Parser::parse_sql`]: crate::parser::Parser::parse_sql
44+
//! [`Parser::new`]: crate::parser::Parser::new
45+
//! [`AST`]: crate::ast
46+
//! [`ast`]: crate::ast
47+
//! [`Dialect`]: crate::dialect::Dialect
4148
4249
#![cfg_attr(not(feature = "std"), no_std)]
4350
#![allow(clippy::upper_case_acronyms)]

0 commit comments

Comments
 (0)