Skip to content

Commit e5d2215

Browse files
authored
Support some of pipe operators (#1759)
1 parent a5b9821 commit e5d2215

File tree

12 files changed

+427
-21
lines changed

12 files changed

+427
-21
lines changed

src/ast/mod.rs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -66,23 +66,23 @@ pub use self::dml::{CreateIndex, CreateTable, Delete, IndexColumn, Insert};
6666
pub use self::operator::{BinaryOperator, UnaryOperator};
6767
pub use self::query::{
6868
AfterMatchSkip, ConnectBy, Cte, CteAsMaterialized, Distinct, EmptyMatchesMode,
69-
ExceptSelectItem, ExcludeSelectItem, ExprWithAlias, Fetch, ForClause, ForJson, ForXml,
70-
FormatClause, GroupByExpr, GroupByWithModifier, IdentWithAlias, IlikeSelectItem,
71-
InputFormatClause, Interpolate, InterpolateExpr, Join, JoinConstraint, JoinOperator,
72-
JsonTableColumn, JsonTableColumnErrorHandling, JsonTableNamedColumn, JsonTableNestedColumn,
73-
LateralView, LimitClause, LockClause, LockType, MatchRecognizePattern, MatchRecognizeSymbol,
74-
Measure, NamedWindowDefinition, NamedWindowExpr, NonBlock, Offset, OffsetRows,
75-
OpenJsonTableColumn, OrderBy, OrderByExpr, OrderByKind, OrderByOptions, PivotValueSource,
76-
ProjectionSelect, Query, RenameSelectItem, RepetitionQuantifier, ReplaceSelectElement,
77-
ReplaceSelectItem, RowsPerMatch, Select, SelectFlavor, SelectInto, SelectItem,
78-
SelectItemQualifiedWildcardKind, SetExpr, SetOperator, SetQuantifier, Setting,
79-
SymbolDefinition, Table, TableAlias, TableAliasColumnDef, TableFactor, TableFunctionArgs,
80-
TableIndexHintForClause, TableIndexHintType, TableIndexHints, TableIndexType, TableSample,
81-
TableSampleBucket, TableSampleKind, TableSampleMethod, TableSampleModifier,
82-
TableSampleQuantity, TableSampleSeed, TableSampleSeedModifier, TableSampleUnit, TableVersion,
83-
TableWithJoins, Top, TopQuantity, UpdateTableFromKind, ValueTableMode, Values,
84-
WildcardAdditionalOptions, With, WithFill, XmlNamespaceDefinition, XmlPassingArgument,
85-
XmlPassingClause, XmlTableColumn, XmlTableColumnOption,
69+
ExceptSelectItem, ExcludeSelectItem, ExprWithAlias, ExprWithAliasAndOrderBy, Fetch, ForClause,
70+
ForJson, ForXml, FormatClause, GroupByExpr, GroupByWithModifier, IdentWithAlias,
71+
IlikeSelectItem, InputFormatClause, Interpolate, InterpolateExpr, Join, JoinConstraint,
72+
JoinOperator, JsonTableColumn, JsonTableColumnErrorHandling, JsonTableNamedColumn,
73+
JsonTableNestedColumn, LateralView, LimitClause, LockClause, LockType, MatchRecognizePattern,
74+
MatchRecognizeSymbol, Measure, NamedWindowDefinition, NamedWindowExpr, NonBlock, Offset,
75+
OffsetRows, OpenJsonTableColumn, OrderBy, OrderByExpr, OrderByKind, OrderByOptions,
76+
PipeOperator, PivotValueSource, ProjectionSelect, Query, RenameSelectItem,
77+
RepetitionQuantifier, ReplaceSelectElement, ReplaceSelectItem, RowsPerMatch, Select,
78+
SelectFlavor, SelectInto, SelectItem, SelectItemQualifiedWildcardKind, SetExpr, SetOperator,
79+
SetQuantifier, Setting, SymbolDefinition, Table, TableAlias, TableAliasColumnDef, TableFactor,
80+
TableFunctionArgs, TableIndexHintForClause, TableIndexHintType, TableIndexHints,
81+
TableIndexType, TableSample, TableSampleBucket, TableSampleKind, TableSampleMethod,
82+
TableSampleModifier, TableSampleQuantity, TableSampleSeed, TableSampleSeedModifier,
83+
TableSampleUnit, TableVersion, TableWithJoins, Top, TopQuantity, UpdateTableFromKind,
84+
ValueTableMode, Values, WildcardAdditionalOptions, With, WithFill, XmlNamespaceDefinition,
85+
XmlPassingArgument, XmlPassingClause, XmlTableColumn, XmlTableColumnOption,
8686
};
8787

8888
pub use self::trigger::{

src/ast/query.rs

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ pub struct Query {
6262
/// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/format)
6363
/// (ClickHouse-specific)
6464
pub format_clause: Option<FormatClause>,
65+
66+
/// Pipe operator
67+
pub pipe_operators: Vec<PipeOperator>,
6568
}
6669

6770
impl fmt::Display for Query {
@@ -92,6 +95,9 @@ impl fmt::Display for Query {
9295
if let Some(ref format) = self.format_clause {
9396
write!(f, " {}", format)?;
9497
}
98+
for pipe_operator in &self.pipe_operators {
99+
write!(f, " |> {}", pipe_operator)?;
100+
}
95101
Ok(())
96102
}
97103
}
@@ -1004,6 +1010,26 @@ impl fmt::Display for ExprWithAlias {
10041010
}
10051011
}
10061012

1013+
/// An expression optionally followed by an alias and order by options.
1014+
///
1015+
/// Example:
1016+
/// ```sql
1017+
/// 42 AS myint ASC
1018+
/// ```
1019+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1020+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1021+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
1022+
pub struct ExprWithAliasAndOrderBy {
1023+
pub expr: ExprWithAlias,
1024+
pub order_by: OrderByOptions,
1025+
}
1026+
1027+
impl fmt::Display for ExprWithAliasAndOrderBy {
1028+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1029+
write!(f, "{}{}", self.expr, self.order_by)
1030+
}
1031+
}
1032+
10071033
/// Arguments to a table-valued function
10081034
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
10091035
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -2513,6 +2539,135 @@ impl fmt::Display for OffsetRows {
25132539
}
25142540
}
25152541

2542+
/// Pipe syntax, first introduced in Google BigQuery.
2543+
/// Example:
2544+
///
2545+
/// ```sql
2546+
/// FROM Produce
2547+
/// |> WHERE sales > 0
2548+
/// |> AGGREGATE SUM(sales) AS total_sales, COUNT(*) AS num_sales
2549+
/// GROUP BY item;
2550+
/// ```
2551+
///
2552+
/// See <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#pipe_syntax>
2553+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2554+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2555+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2556+
pub enum PipeOperator {
2557+
/// Limits the number of rows to return in a query, with an optional OFFSET clause to skip over rows.
2558+
///
2559+
/// Syntax: `|> LIMIT <n> [OFFSET <m>]`
2560+
///
2561+
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#limit_pipe_operator>
2562+
Limit { expr: Expr, offset: Option<Expr> },
2563+
/// Filters the results of the input table.
2564+
///
2565+
/// Syntax: `|> WHERE <condition>`
2566+
///
2567+
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#where_pipe_operator>
2568+
Where { expr: Expr },
2569+
/// `ORDER BY <expr> [ASC|DESC], ...`
2570+
OrderBy { exprs: Vec<OrderByExpr> },
2571+
/// Produces a new table with the listed columns, similar to the outermost SELECT clause in a table subquery in standard syntax.
2572+
///
2573+
/// Syntax `|> SELECT <expr> [[AS] alias], ...`
2574+
///
2575+
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#select_pipe_operator>
2576+
Select { exprs: Vec<SelectItem> },
2577+
/// Propagates the existing table and adds computed columns, similar to SELECT *, new_column in standard syntax.
2578+
///
2579+
/// Syntax: `|> EXTEND <expr> [[AS] alias], ...`
2580+
///
2581+
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#extend_pipe_operator>
2582+
Extend { exprs: Vec<SelectItem> },
2583+
/// Replaces the value of a column in the current table, similar to SELECT * REPLACE (expression AS column) in standard syntax.
2584+
///
2585+
/// Syntax: `|> SET <column> = <expression>, ...`
2586+
///
2587+
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#set_pipe_operator>
2588+
Set { assignments: Vec<Assignment> },
2589+
/// Removes listed columns from the current table, similar to SELECT * EXCEPT (column) in standard syntax.
2590+
///
2591+
/// Syntax: `|> DROP <column>, ...`
2592+
///
2593+
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#drop_pipe_operator>
2594+
Drop { columns: Vec<Ident> },
2595+
/// Introduces a table alias for the input table, similar to applying the AS alias clause on a table subquery in standard syntax.
2596+
///
2597+
/// Syntax: `|> AS <alias>`
2598+
///
2599+
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#as_pipe_operator>
2600+
As { alias: Ident },
2601+
/// Performs aggregation on data across grouped rows or an entire table.
2602+
///
2603+
/// Syntax: `|> AGGREGATE <agg_expr> [[AS] alias], ...`
2604+
///
2605+
/// Syntax:
2606+
/// ```norust
2607+
/// |> AGGREGATE [<agg_expr> [[AS] alias], ...]
2608+
/// GROUP BY <grouping_expr> [AS alias], ...
2609+
/// ```
2610+
///
2611+
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#aggregate_pipe_operator>
2612+
Aggregate {
2613+
full_table_exprs: Vec<ExprWithAliasAndOrderBy>,
2614+
group_by_expr: Vec<ExprWithAliasAndOrderBy>,
2615+
},
2616+
}
2617+
2618+
impl fmt::Display for PipeOperator {
2619+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2620+
match self {
2621+
PipeOperator::Select { exprs } => {
2622+
write!(f, "SELECT {}", display_comma_separated(exprs.as_slice()))
2623+
}
2624+
PipeOperator::Extend { exprs } => {
2625+
write!(f, "EXTEND {}", display_comma_separated(exprs.as_slice()))
2626+
}
2627+
PipeOperator::Set { assignments } => {
2628+
write!(f, "SET {}", display_comma_separated(assignments.as_slice()))
2629+
}
2630+
PipeOperator::Drop { columns } => {
2631+
write!(f, "DROP {}", display_comma_separated(columns.as_slice()))
2632+
}
2633+
PipeOperator::As { alias } => {
2634+
write!(f, "AS {}", alias)
2635+
}
2636+
PipeOperator::Limit { expr, offset } => {
2637+
write!(f, "LIMIT {}", expr)?;
2638+
if let Some(offset) = offset {
2639+
write!(f, " OFFSET {}", offset)?;
2640+
}
2641+
Ok(())
2642+
}
2643+
PipeOperator::Aggregate {
2644+
full_table_exprs,
2645+
group_by_expr,
2646+
} => {
2647+
write!(f, "AGGREGATE")?;
2648+
if !full_table_exprs.is_empty() {
2649+
write!(
2650+
f,
2651+
" {}",
2652+
display_comma_separated(full_table_exprs.as_slice())
2653+
)?;
2654+
}
2655+
if !group_by_expr.is_empty() {
2656+
write!(f, " GROUP BY {}", display_comma_separated(group_by_expr))?;
2657+
}
2658+
Ok(())
2659+
}
2660+
2661+
PipeOperator::Where { expr } => {
2662+
write!(f, "WHERE {}", expr)
2663+
}
2664+
PipeOperator::OrderBy { exprs } => {
2665+
write!(f, "ORDER BY {}", display_comma_separated(exprs.as_slice()))
2666+
}
2667+
}
2668+
}
2669+
}
2670+
25162671
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
25172672
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25182673
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]

src/ast/spans.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,11 @@ impl Spanned for Query {
9898
order_by,
9999
limit_clause,
100100
fetch,
101-
locks: _, // todo
102-
for_clause: _, // todo, mssql specific
103-
settings: _, // todo, clickhouse specific
104-
format_clause: _, // todo, clickhouse specific
101+
locks: _, // todo
102+
for_clause: _, // todo, mssql specific
103+
settings: _, // todo, clickhouse specific
104+
format_clause: _, // todo, clickhouse specific
105+
pipe_operators: _, // todo bigquery specific
105106
} = self;
106107

107108
union_spans(

src/dialect/bigquery.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ impl Dialect for BigQueryDialect {
136136
fn is_column_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
137137
!RESERVED_FOR_COLUMN_ALIAS.contains(kw)
138138
}
139+
140+
fn supports_pipe_operator(&self) -> bool {
141+
true
142+
}
139143
}
140144

141145
impl BigQueryDialect {

src/dialect/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,20 @@ pub trait Dialect: Debug + Any {
518518
false
519519
}
520520

521+
/// Return true if the dialect supports pipe operator.
522+
///
523+
/// Example:
524+
/// ```sql
525+
/// SELECT *
526+
/// FROM table
527+
/// |> limit 1
528+
/// ```
529+
///
530+
/// See <https://cloud.google.com/bigquery/docs/pipe-syntax-guide#basic_syntax>
531+
fn supports_pipe_operator(&self) -> bool {
532+
false
533+
}
534+
521535
/// Does the dialect support MySQL-style `'user'@'host'` grantee syntax?
522536
fn supports_user_host_grantee(&self) -> bool {
523537
false

src/keywords.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ define_keywords!(
8383
ADMIN,
8484
AFTER,
8585
AGAINST,
86+
AGGREGATE,
8687
AGGREGATION,
8788
ALERT,
8889
ALGORITHM,
@@ -338,6 +339,7 @@ define_keywords!(
338339
EXPLAIN,
339340
EXPLICIT,
340341
EXPORT,
342+
EXTEND,
341343
EXTENDED,
342344
EXTENSION,
343345
EXTERNAL,

0 commit comments

Comments
 (0)