Skip to content

Commit

Permalink
feat(sqlparser-rs#757): Add Location/Spans in to the AST/parse layer
Browse files Browse the repository at this point in the history
  • Loading branch information
jakeswenson committed Mar 19, 2023
1 parent a8a8e65 commit 4e66a81
Show file tree
Hide file tree
Showing 14 changed files with 816 additions and 456 deletions.
137 changes: 102 additions & 35 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::borrow::Borrow;
use core::fmt;
use std::ops::Deref;

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
Expand All @@ -44,6 +46,7 @@ pub use self::value::{
escape_quoted_string, DateTimeField, DollarQuotedString, TrimWhereField, Value,
};

use crate::tokenizer::Span;
#[cfg(feature = "visitor")]
pub use visitor::*;

Expand Down Expand Up @@ -251,6 +254,76 @@ impl fmt::Display for JsonOperator {
}
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct WithSpan<T>
where
T: Clone + Eq + Ord + std::hash::Hash + PartialOrd + PartialEq,
{
inner: T,
span: Span,
}

impl<T> WithSpan<T>
where
T: Clone + Eq + Ord + std::hash::Hash + PartialOrd + PartialEq,
{
pub fn new(inner: T, span: Span) -> Self {
Self { inner, span }
}

pub fn unwrap(self) -> T {
self.inner
}
}

pub trait SpanWrapped: Clone + Eq + Ord + std::hash::Hash + PartialOrd + PartialEq {
fn spanning<U: Into<Span>>(self, span: U) -> WithSpan<Self> {
WithSpan::new(self, span.into())
}

fn empty_span(self) -> WithSpan<Self> {
self.spanning(Span::default())
}
}

impl<T> SpanWrapped for T
where
T: Clone + Eq + Ord + std::hash::Hash + PartialOrd + PartialEq,
{
fn spanning<U: Into<Span>>(self, span: U) -> WithSpan<Self> {
WithSpan::new(self, span.into())
}
}

impl<T> Deref for WithSpan<T>
where
T: Clone + Eq + Ord + std::hash::Hash + PartialOrd + PartialEq,
{
type Target = T;

fn deref(&self) -> &Self::Target {
&self.inner
}
}

impl<T> Borrow<T> for WithSpan<T>
where
T: Clone + Eq + Ord + std::hash::Hash + PartialOrd + PartialEq,
{
fn borrow(&self) -> &T {
&self.inner
}
}

impl<T: fmt::Display> fmt::Display for WithSpan<T>
where
T: Clone + Eq + Ord + std::hash::Hash + PartialOrd + PartialEq,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.inner)
}
}

/// An SQL expression of any type.
///
/// The parser does not distinguish between expressions of different types
Expand All @@ -265,7 +338,7 @@ impl fmt::Display for JsonOperator {
)]
pub enum Expr {
/// Identifier e.g. table name or column name
Identifier(Ident),
Identifier(WithSpan<Ident>),
/// Multi-part identifier, e.g. `table_alias.column` or `schema.table.col`
CompoundIdentifier(Vec<Ident>),
/// JSON access (postgres) eg: data->'tags'
Expand Down Expand Up @@ -4162,6 +4235,12 @@ impl fmt::Display for SearchModifier {
mod tests {
use super::*;

fn ident<T: Into<String>>(value: T) -> WithSpan<Ident> {
use crate::ast::SpanWrapped;

SpanWrapped::empty_span(Ident::new(value))
}

#[test]
fn test_window_frame_default() {
let window_frame = WindowFrame::default();
Expand All @@ -4172,84 +4251,72 @@ mod tests {
fn test_grouping_sets_display() {
// a and b in different group
let grouping_sets = Expr::GroupingSets(vec![
vec![Expr::Identifier(Ident::new("a"))],
vec![Expr::Identifier(Ident::new("b"))],
vec![Expr::Identifier(ident("a"))],
vec![Expr::Identifier(ident("b"))],
]);
assert_eq!("GROUPING SETS ((a), (b))", format!("{grouping_sets}"));

// a and b in the same group
let grouping_sets = Expr::GroupingSets(vec![vec![
Expr::Identifier(Ident::new("a")),
Expr::Identifier(Ident::new("b")),
Expr::Identifier(ident("a")),
Expr::Identifier(ident("b")),
]]);
assert_eq!("GROUPING SETS ((a, b))", format!("{grouping_sets}"));

// (a, b) and (c, d) in different group
let grouping_sets = Expr::GroupingSets(vec![
vec![
Expr::Identifier(Ident::new("a")),
Expr::Identifier(Ident::new("b")),
],
vec![
Expr::Identifier(Ident::new("c")),
Expr::Identifier(Ident::new("d")),
],
vec![Expr::Identifier(ident("a")), Expr::Identifier(ident("b"))],
vec![Expr::Identifier(ident("c")), Expr::Identifier(ident("d"))],
]);
assert_eq!("GROUPING SETS ((a, b), (c, d))", format!("{grouping_sets}"));
}

#[test]
fn test_rollup_display() {
let rollup = Expr::Rollup(vec![vec![Expr::Identifier(Ident::new("a"))]]);
let rollup = Expr::Rollup(vec![vec![Expr::Identifier(ident("a"))]]);
assert_eq!("ROLLUP (a)", format!("{rollup}"));

let rollup = Expr::Rollup(vec![vec![
Expr::Identifier(Ident::new("a")),
Expr::Identifier(Ident::new("b")),
Expr::Identifier(ident("a")),
Expr::Identifier(ident("b")),
]]);
assert_eq!("ROLLUP ((a, b))", format!("{rollup}"));

let rollup = Expr::Rollup(vec![
vec![Expr::Identifier(Ident::new("a"))],
vec![Expr::Identifier(Ident::new("b"))],
vec![Expr::Identifier(ident("a"))],
vec![Expr::Identifier(ident("b"))],
]);
assert_eq!("ROLLUP (a, b)", format!("{rollup}"));

let rollup = Expr::Rollup(vec![
vec![Expr::Identifier(Ident::new("a"))],
vec![
Expr::Identifier(Ident::new("b")),
Expr::Identifier(Ident::new("c")),
],
vec![Expr::Identifier(Ident::new("d"))],
vec![Expr::Identifier(ident("a"))],
vec![Expr::Identifier(ident("b")), Expr::Identifier(ident("c"))],
vec![Expr::Identifier(ident("d"))],
]);
assert_eq!("ROLLUP (a, (b, c), d)", format!("{rollup}"));
}

#[test]
fn test_cube_display() {
let cube = Expr::Cube(vec![vec![Expr::Identifier(Ident::new("a"))]]);
let cube = Expr::Cube(vec![vec![Expr::Identifier(ident("a"))]]);
assert_eq!("CUBE (a)", format!("{cube}"));

let cube = Expr::Cube(vec![vec![
Expr::Identifier(Ident::new("a")),
Expr::Identifier(Ident::new("b")),
Expr::Identifier(ident("a")),
Expr::Identifier(ident("b")),
]]);
assert_eq!("CUBE ((a, b))", format!("{cube}"));

let cube = Expr::Cube(vec![
vec![Expr::Identifier(Ident::new("a"))],
vec![Expr::Identifier(Ident::new("b"))],
vec![Expr::Identifier(ident("a"))],
vec![Expr::Identifier(ident("b"))],
]);
assert_eq!("CUBE (a, b)", format!("{cube}"));

let cube = Expr::Cube(vec![
vec![Expr::Identifier(Ident::new("a"))],
vec![
Expr::Identifier(Ident::new("b")),
Expr::Identifier(Ident::new("c")),
],
vec![Expr::Identifier(Ident::new("d"))],
vec![Expr::Identifier(ident("a"))],
vec![Expr::Identifier(ident("b")), Expr::Identifier(ident("c"))],
vec![Expr::Identifier(ident("d"))],
]);
assert_eq!("CUBE (a, (b, c), d)", format!("{cube}"));
}
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ extern crate alloc;
#[macro_use]
#[cfg(test)]
extern crate pretty_assertions;
extern crate core;

pub mod ast;
#[macro_use]
Expand Down

0 comments on commit 4e66a81

Please sign in to comment.