diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 07bb67bef..836d55614 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -35,6 +35,16 @@ jobs: - uses: actions/checkout@master - run: cargo check --all-targets --all-features + docs: + runs-on: ubuntu-latest + env: + RUSTDOCFLAGS: "-Dwarnings" + steps: + - name: Set up Rust + uses: hecrj/setup-rust-action@v1 + - uses: actions/checkout@master + - run: cargo doc --document-private-items --no-deps --workspace --all-features + compile-no-std: runs-on: ubuntu-latest steps: diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs index e5bee49ca..612f79131 100644 --- a/src/ast/ddl.rs +++ b/src/ast/ddl.rs @@ -10,7 +10,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! AST types specific to CREATE/ALTER variants of [Statement] +//! AST types specific to CREATE/ALTER variants of [`Statement`](crate::ast::Statement) //! (commonly referred to as Data Definition Language, or DDL) #[cfg(not(feature = "std"))] @@ -325,6 +325,7 @@ pub enum TableConstraint { /// ``` /// /// [1]: https://dev.mysql.com/doc/refman/8.0/en/fulltext-natural-language.html + /// [2]: https://dev.mysql.com/doc/refman/8.0/en/spatial-types.html FulltextOrSpatial { /// Whether this is a `FULLTEXT` (true) or `SPATIAL` (false) definition. fulltext: bool, diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 80dff8504..c5471b2cc 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -370,39 +370,52 @@ pub enum Expr { timestamp: Box, time_zone: String, }, + /// ```sql /// EXTRACT(DateTimeField FROM ) + /// ``` Extract { field: DateTimeField, expr: Box, }, + /// ```sql /// CEIL( [TO DateTimeField]) + /// ``` Ceil { expr: Box, field: DateTimeField, }, + /// ```sql /// FLOOR( [TO DateTimeField]) + /// ``` Floor { expr: Box, field: DateTimeField, }, + /// ```sql /// POSITION( in ) + /// ``` Position { expr: Box, r#in: Box }, + /// ```sql /// SUBSTRING( [FROM ] [FOR ]) + /// ``` Substring { expr: Box, substring_from: Option>, substring_for: Option>, }, - /// TRIM([BOTH | LEADING | TRAILING] [ FROM] )\ - /// Or\ + /// ```sql + /// TRIM([BOTH | LEADING | TRAILING] [ FROM] ) /// TRIM() + /// ``` Trim { expr: Box, // ([BOTH | LEADING | TRAILING] trim_where: Option, trim_what: Option>, }, + /// ```sql /// OVERLAY( PLACING FROM [ FOR ] + /// ``` Overlay { expr: Box, overlay_what: Box, @@ -424,7 +437,7 @@ pub enum Expr { TypedString { data_type: DataType, value: String }, /// Access a map-like object by field (e.g. `column['field']` or `column[4]` /// Note that depending on the dialect, struct like accesses may be - /// parsed as [`ArrayIndex`] or [`MapAccess`] + /// parsed as [`ArrayIndex`](Self::ArrayIndex) or [`MapAccess`](Self::MapAccess) /// MapAccess { column: Box, keys: Vec }, /// Scalar function call e.g. `LEFT(foo, 5)` @@ -488,7 +501,7 @@ pub enum Expr { /// `MySQL` specific text search function [(1)]. /// /// Syntax: - /// ```text + /// ```sql /// MARCH (, , ...) AGAINST ( []) /// /// = CompoundIdentifier @@ -954,9 +967,9 @@ pub struct WindowFrame { } impl Default for WindowFrame { - /// returns default value for window frame + /// Returns default value for window frame /// - /// see https://www.sqlite.org/windowfunctions.html#frame_specifications + /// See [this page](https://www.sqlite.org/windowfunctions.html#frame_specifications) for more details. fn default() -> Self { Self { units: WindowFrameUnits::Range, @@ -1363,7 +1376,9 @@ pub enum Statement { /// Role name. If NONE is specified, then the current role name is removed. role_name: Option, }, + /// ```sql /// SET + /// ``` /// /// Note: this is not a standard SQL statement, but it is supported by at /// least MySQL and PostgreSQL. Not all MySQL-specific syntatic forms are @@ -1374,10 +1389,12 @@ pub enum Statement { variable: ObjectName, value: Vec, }, + /// ```sql /// SET TIME ZONE + /// ``` /// /// Note: this is a PostgreSQL-specific statements - /// SET TIME ZONE is an alias for SET timezone TO in PostgreSQL + /// `SET TIME ZONE ` is an alias for `SET timezone TO ` in PostgreSQL SetTimeZone { local: bool, value: Expr }, /// SET NAMES 'charset_name' [COLLATE 'collation_name'] /// @@ -1394,7 +1411,9 @@ pub enum Statement { /// /// Note: this is a Presto-specific statement. ShowFunctions { filter: Option }, + /// ```sql /// SHOW + /// ``` /// /// Note: this is a PostgreSQL-specific statement. ShowVariable { variable: Vec }, @@ -1469,10 +1488,13 @@ pub enum Statement { location: Option, managed_location: Option, }, + /// ```sql /// CREATE FUNCTION + /// ``` /// - /// Hive: https://cwiki.apache.org/confluence/display/hive/languagemanual+ddl#LanguageManualDDL-Create/Drop/ReloadFunction - /// Postgres: https://www.postgresql.org/docs/15/sql-createfunction.html + /// Supported variants: + /// 1. [Hive](https://cwiki.apache.org/confluence/display/hive/languagemanual+ddl#LanguageManualDDL-Create/Drop/ReloadFunction) + /// 2. [Postgres](https://www.postgresql.org/docs/15/sql-createfunction.html) CreateFunction { or_replace: bool, temporary: bool, @@ -1565,8 +1587,11 @@ pub enum Statement { // Specifies the actions to perform when values match or do not match. clauses: Vec, }, - /// CACHE [ FLAG ] TABLE [ OPTIONS('K1' = 'V1', 'K2' = V2) ] [ AS ] [ ] - /// Based on Spark SQL,see + /// `CACHE [ FLAG ] TABLE [ OPTIONS('K1' = 'V1', 'K2' = V2) ] [ AS ] [ ]`. + /// + /// See [Spark SQL docs] for more details. + /// + /// [Spark SQL docs]: https://docs.databricks.com/spark/latest/spark-sql/language-manual/sql-ref-syntax-aux-cache-cache-table.html Cache { /// Table flag table_flag: Option, @@ -2705,9 +2730,11 @@ impl fmt::Display for Statement { } /// Can use to describe options in create sequence or table column type identity +/// ```sql /// [ INCREMENT [ BY ] increment ] /// [ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ] /// [ START [ WITH ] start ] [ CACHE cache ] [ [ NO ] CYCLE ] +/// ``` #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit))] @@ -3538,7 +3565,8 @@ impl fmt::Display for ShowStatementFilter { /// Sqlite specific syntax /// -/// https://sqlite.org/lang_conflict.html +/// See [Sqlite documentation](https://sqlite.org/lang_conflict.html) +/// for more details. #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit))] @@ -3977,7 +4005,10 @@ impl fmt::Display for FunctionDefinition { } } -/// Postgres: https://www.postgresql.org/docs/15/sql-createfunction.html +/// Postgres specific feature. +/// +/// See [Postgresdocs](https://www.postgresql.org/docs/15/sql-createfunction.html) +/// for more details #[derive(Debug, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit))] diff --git a/src/ast/query.rs b/src/ast/query.rs index 7a009c2ed..0a01cf33c 100644 --- a/src/ast/query.rs +++ b/src/ast/query.rs @@ -529,6 +529,7 @@ pub enum TableFactor { expr: Expr, alias: Option, }, + /// ```sql /// SELECT * FROM UNNEST ([10,20,30]) as numbers WITH OFFSET; /// +---------+--------+ /// | numbers | offset | @@ -537,6 +538,7 @@ pub enum TableFactor { /// | 20 | 1 | /// | 30 | 2 | /// +---------+--------+ + /// ``` UNNEST { alias: Option, array_expr: Box, diff --git a/src/ast/value.rs b/src/ast/value.rs index e17f464cf..a3dc190b9 100644 --- a/src/ast/value.rs +++ b/src/ast/value.rs @@ -36,7 +36,8 @@ pub enum Value { /// 'string value' SingleQuotedString(String), /// e'string value' (postgres extension) - /// bool { false } - /// Returns true if the dialect supports ARRAY_AGG() [WITHIN GROUP (ORDER BY)] expressions. - /// Otherwise, the dialect should expect an `ORDER BY` without the `WITHIN GROUP` clause, e.g. `ANSI` [(1)]. - /// [(1)]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#array-aggregate-function + /// Returns true if the dialect supports `ARRAY_AGG() [WITHIN GROUP (ORDER BY)]` expressions. + /// Otherwise, the dialect should expect an `ORDER BY` without the `WITHIN GROUP` clause, e.g. [`ANSI`] + /// + /// [`ANSI`]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#array-aggregate-function fn supports_within_after_array_aggregation(&self) -> bool { false } diff --git a/src/keywords.rs b/src/keywords.rs index 137692610..ac8f28ac2 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -11,9 +11,7 @@ // limitations under the License. //! This module defines -//! 1) a list of constants for every keyword that -//! can appear in [Word::keyword]: -//! pub const KEYWORD = "KEYWORD" +//! 1) a list of constants for every keyword //! 2) an `ALL_KEYWORDS` array with every keyword in it //! This is not a list of *reserved* keywords: some of these can be //! parsed as identifiers if the parser decides so. This means that diff --git a/src/parser.rs b/src/parser.rs index ba62ff9b7..4ad235b02 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1180,8 +1180,10 @@ impl<'a> Parser<'a> { }) } - /// TRIM ([WHERE] ['text' FROM] 'text')\ + /// ```sql + /// TRIM ([WHERE] ['text' FROM] 'text') /// TRIM ('text') + /// ``` pub fn parse_trim_expr(&mut self) -> Result { self.expect_token(&Token::LParen)?; let mut trim_where = None; @@ -2983,8 +2985,10 @@ impl<'a> Parser<'a> { }) } + /// ```sql /// DROP FUNCTION [ IF EXISTS ] name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] [, ...] /// [ CASCADE | RESTRICT ] + /// ``` fn parse_drop_function(&mut self) -> Result { let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]); let func_desc = self.parse_comma_separated(Parser::parse_drop_function_desc)?; @@ -3018,8 +3022,10 @@ impl<'a> Parser<'a> { Ok(DropFunctionDesc { name, args }) } + /// ```sql /// DECLARE name [ BINARY ] [ ASENSITIVE | INSENSITIVE ] [ [ NO ] SCROLL ] - // CURSOR [ { WITH | WITHOUT } HOLD ] FOR query + /// CURSOR [ { WITH | WITHOUT } HOLD ] FOR query + /// ``` pub fn parse_declare(&mut self) -> Result { let name = self.parse_identifier()?; @@ -4835,7 +4841,7 @@ impl<'a> Parser<'a> { /// Parse a "query body", which is an expression with roughly the /// following grammar: - /// ```text + /// ```sql /// query_body ::= restricted_select | '(' subquery ')' | set_operation /// restricted_select ::= 'SELECT' [expr_list] [ from ] [ where ] [ groupby_having ] /// subquery ::= query_body [ order_by_limit ] @@ -6143,7 +6149,7 @@ impl<'a> Parser<'a> { } /// Parse a TOP clause, MSSQL equivalent of LIMIT, - /// that follows after SELECT [DISTINCT]. + /// that follows after `SELECT [DISTINCT]`. pub fn parse_top(&mut self) -> Result { let quantity = if self.consume_token(&Token::LParen) { let quantity = self.parse_expr()?; @@ -6462,8 +6468,11 @@ impl<'a> Parser<'a> { }) } - /// https://www.postgresql.org/docs/current/sql-createsequence.html + /// ```sql /// CREATE [ { TEMPORARY | TEMP } ] SEQUENCE [ IF NOT EXISTS ] + /// ``` + /// + /// See [Postgres docs](https://www.postgresql.org/docs/current/sql-createsequence.html) for more details. pub fn parse_create_sequence(&mut self, temporary: bool) -> Result { //[ IF NOT EXISTS ] let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);