Skip to content

Commit

Permalink
feat: Implement ORDER BY ... USING <operator> feature
Browse files Browse the repository at this point in the history
  • Loading branch information
AmrDeveloper committed Sep 22, 2024
1 parent 34718ac commit 4dbcb95
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 16 deletions.
2 changes: 1 addition & 1 deletion crates/gitql-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
pub mod combinations_generator;
pub mod dynamic_types;
pub mod environment;
pub mod name_generator;
pub mod object;
pub mod schema;
pub mod signature;
pub mod types;
pub mod value;
pub mod name_generator;
2 changes: 1 addition & 1 deletion crates/gitql-engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ pub mod engine_evaluator;
pub mod engine_executor;
pub mod engine_filter;
pub mod engine_group;
pub mod engine_join;
pub mod engine_join;
2 changes: 1 addition & 1 deletion crates/gitql-parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ pub mod diagnostic;
pub mod format_checker;
pub mod parser;
pub mod tokenizer;
pub mod type_checker;
pub mod type_checker;
64 changes: 51 additions & 13 deletions crates/gitql-parser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1152,20 +1152,9 @@ fn parse_order_by_statement(
let mut sorting_orders: Vec<SortingOrder> = vec![];

loop {
let argument = parse_expression(context, env, tokens, position)?;
arguments.push(argument);
arguments.push(parse_expression(context, env, tokens, position)?);
sorting_orders.push(parse_sorting_order(tokens, position)?);

let mut order = SortingOrder::Ascending;
if *position < tokens.len() && is_asc_or_desc(&tokens[*position]) {
if tokens[*position].kind == TokenKind::Descending {
order = SortingOrder::Descending;
}

// Consume `ASC or DESC` keyword
*position += 1;
}

sorting_orders.push(order);
if *position < tokens.len() && tokens[*position].kind == TokenKind::Comma {
// Consume `,` keyword
*position += 1;
Expand All @@ -1180,6 +1169,50 @@ fn parse_order_by_statement(
}))
}

fn parse_sorting_order(
tokens: &[Token],
position: &mut usize,
) -> Result<SortingOrder, Box<Diagnostic>> {
let mut sorting_order = SortingOrder::Ascending;
if *position >= tokens.len() {
return Ok(sorting_order);
}

// Parse `ASC` or `DESC`
if is_asc_or_desc(&tokens[*position]) {
if tokens[*position].kind == TokenKind::Descending {
sorting_order = SortingOrder::Descending;
}

// Consume `ASC or DESC` keyword
*position += 1;
return Ok(sorting_order);
}

// Parse `USING <Operator>`
if tokens[*position].kind == TokenKind::Using {
// Consume `USING` keyword
*position += 1;

if *position < tokens.len() && is_order_by_using_operator(&tokens[*position]) {
if tokens[*position].kind == TokenKind::Greater {
sorting_order = SortingOrder::Descending;
}

// Consume `> or <` keyword
*position += 1;
return Ok(sorting_order);
}

return Err(Diagnostic::error("Expect `>` or `<` after `USING` keyword")
.with_location(tokens[*position - 1].location)
.as_boxed());
}

// Return default sorting order
Ok(sorting_order)
}

fn parse_into_statement(
tokens: &[Token],
position: &mut usize,
Expand Down Expand Up @@ -3247,6 +3280,11 @@ fn is_factor_operator(token: &Token) -> bool {
|| token.kind == TokenKind::Caret
}

#[inline(always)]
fn is_order_by_using_operator(token: &Token) -> bool {
token.kind == TokenKind::Greater || token.kind == TokenKind::Less
}

#[inline(always)]
fn is_join_token(token: &Token) -> bool {
token.kind == TokenKind::Join
Expand Down
2 changes: 2 additions & 0 deletions crates/gitql-parser/src/tokenizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub enum TokenKind {
Limit,
Offset,
Order,
Using,
By,
In,
Is,
Expand Down Expand Up @@ -1141,6 +1142,7 @@ fn resolve_symbol_kind(literal: String) -> TokenKind {
"limit" => TokenKind::Limit,
"offset" => TokenKind::Offset,
"order" => TokenKind::Order,
"using" => TokenKind::Using,
"case" => TokenKind::Case,
"when" => TokenKind::When,
"then" => TokenKind::Then,
Expand Down
7 changes: 7 additions & 0 deletions docs/statement/order_by.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,10 @@ SELECT author_name, author_email FROM commits ORDER BY author_email, commit_id A
SELECT author_name, author_email FROM commits ORDER BY author_name DESC
SELECT author_name, author_email FROM commits ORDER BY author_name, LEN(author_name)
```

The `ORDER BY` Statement with `USING <operator>` syntax inspired by PostgreSQL

```sql
SELECT author_name, author_email FROM commits ORDER BY author_email, commit_id USING <
SELECT author_name, author_email FROM commits ORDER BY author_name USING >
```

0 comments on commit 4dbcb95

Please sign in to comment.