From 979c0cb1ce8f7762fca3c7b68c7055e9c6b63f32 Mon Sep 17 00:00:00 2001 From: Josh Pschorr Date: Thu, 25 Jul 2024 13:11:50 -0700 Subject: [PATCH] Add Parsing of `EXCLUDE` (#480) --- CHANGELOG.md | 3 + partiql-ast/src/ast.rs | 28 +++ partiql-ast/src/pretty.rs | 52 ++++++ partiql-ast/src/visit.rs | 18 ++ partiql-logical-planner/src/lower.rs | 6 +- partiql-parser/src/lexer.rs | 3 + partiql-parser/src/parse/partiql.lalrpop | 66 ++++++- partiql-parser/src/preprocessor.rs | 4 +- partiql/tests/pretty.rs | 101 +++++++++++ .../snapshots/pretty__pretty_exclude_1.snap | 110 ++++++++++++ .../snapshots/pretty__pretty_exclude_2.snap | 127 ++++++++++++++ .../snapshots/pretty__pretty_exclude_3.snap | 164 ++++++++++++++++++ .../snapshots/pretty__pretty_exclude_4.snap | 161 +++++++++++++++++ 13 files changed, 832 insertions(+), 11 deletions(-) create mode 100644 partiql/tests/snapshots/pretty__pretty_exclude_1.snap create mode 100644 partiql/tests/snapshots/pretty__pretty_exclude_2.snap create mode 100644 partiql/tests/snapshots/pretty__pretty_exclude_3.snap create mode 100644 partiql/tests/snapshots/pretty__pretty_exclude_4.snap diff --git a/CHANGELOG.md b/CHANGELOG.md index 96ce2461..89b60158 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Changed +- *BREAKING:* partiql-ast: added modeling of `EXCLUDE` +- *BREAKING:* partiql-ast: added pretty-printing of `EXCLUDE` ### Added +- *BREAKING:* partiql-parser: added parsing of `EXCLUDE` ### Fixed diff --git a/partiql-ast/src/ast.rs b/partiql-ast/src/ast.rs index 5b9e7d94..de13bb2d 100644 --- a/partiql-ast/src/ast.rs +++ b/partiql-ast/src/ast.rs @@ -311,6 +311,7 @@ pub enum SetQuantifier { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Select { pub project: AstNode, + pub exclude: Option>, pub from: Option>, pub from_let: Option>, pub where_clause: Option>>, @@ -375,6 +376,12 @@ pub struct ProjectExpr { pub as_alias: Option, } +#[derive(Visit, Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Exclusion { + pub items: Vec>, +} + /// The expressions that can result in values. #[derive(Visit, Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] @@ -690,6 +697,27 @@ pub struct PathExpr { pub index: Box, } +#[derive(Visit, Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct ExcludePath { + pub root: AstNode, + pub steps: Vec, +} + +/// A "step" within an exclude path; that is the components of the exclude path following the root. +#[derive(Visit, Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub enum ExcludePathStep { + #[visit(skip)] + PathProject(AstNode), + #[visit(skip)] + PathIndex(AstNode), + #[visit(skip)] + PathForEach, + #[visit(skip)] + PathUnpivot, +} + #[derive(Visit, Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Let { diff --git a/partiql-ast/src/pretty.rs b/partiql-ast/src/pretty.rs index 9b812966..b1cb69de 100644 --- a/partiql-ast/src/pretty.rs +++ b/partiql-ast/src/pretty.rs @@ -213,8 +213,19 @@ impl PrettyDoc for Select { D::Doc: Clone, A: Clone, { + fn delegate<'b, C, D, A>(child: &'b Option, arena: &'b D) -> Option> + where + D: DocAllocator<'b, A>, + D::Doc: Clone, + A: Clone, + C: PrettyDoc, + { + child.as_ref().map(|inner| inner.pretty_doc(arena).group()) + } + let Select { project, + exclude, from, from_let, where_clause, @@ -223,6 +234,7 @@ impl PrettyDoc for Select { } = self; let clauses = [ Some(project.pretty_doc(arena).group()), + delegate(exclude, arena), from.as_ref().map(|inner| inner.pretty_doc(arena).group()), from_let .as_ref() @@ -313,6 +325,46 @@ impl PrettyDoc for ProjectExpr { } } +impl PrettyDoc for Exclusion { + fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A> + where + D: DocAllocator<'b, A>, + D::Doc: Clone, + A: Clone, + { + pretty_annotated_doc( + "EXCLUDE", + pretty_list(&self.items, MINOR_NEST_INDENT, arena), + arena, + ) + } +} + +impl PrettyDoc for ExcludePath { + fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A> + where + D: DocAllocator<'b, A>, + D::Doc: Clone, + A: Clone, + { + let ExcludePath { root, steps } = self; + let mut path = root.pretty_doc(arena); + for step in steps { + path = path.append(match step { + ExcludePathStep::PathProject(e) => arena.text(".").append(e.pretty_doc(arena)), + ExcludePathStep::PathIndex(e) => arena + .text("[") + .append(e.pretty_doc(arena)) + .append(arena.text("]")), + ExcludePathStep::PathForEach => arena.text("[*]"), + ExcludePathStep::PathUnpivot => arena.text(".*"), + }); + } + + path + } +} + impl PrettyDoc for Expr { fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A> where diff --git a/partiql-ast/src/visit.rs b/partiql-ast/src/visit.rs index 9a6de413..19acad7b 100644 --- a/partiql-ast/src/visit.rs +++ b/partiql-ast/src/visit.rs @@ -291,6 +291,24 @@ pub trait Visitor<'ast> { fn exit_project_expr(&mut self, _project_expr: &'ast ast::ProjectExpr) -> Traverse { Traverse::Continue } + fn enter_exclusion(&mut self, _exclusion: &'ast ast::Exclusion) -> Traverse { + Traverse::Continue + } + fn exit_exclusion(&mut self, _exclusion: &'ast ast::Exclusion) -> Traverse { + Traverse::Continue + } + fn enter_exclude_path(&mut self, _path: &'ast ast::ExcludePath) -> Traverse { + Traverse::Continue + } + fn exit_exclude_path(&mut self, _path: &'ast ast::ExcludePath) -> Traverse { + Traverse::Continue + } + fn enter_exclude_path_step(&mut self, _step: &'ast ast::ExcludePathStep) -> Traverse { + Traverse::Continue + } + fn exit_exclude_path_step(&mut self, _step: &'ast ast::ExcludePathStep) -> Traverse { + Traverse::Continue + } fn enter_expr(&mut self, _expr: &'ast ast::Expr) -> Traverse { Traverse::Continue } diff --git a/partiql-logical-planner/src/lower.rs b/partiql-logical-planner/src/lower.rs index 6499ace6..3a7bd23c 100644 --- a/partiql-logical-planner/src/lower.rs +++ b/partiql-logical-planner/src/lower.rs @@ -6,7 +6,7 @@ use partiql_ast::ast; use partiql_ast::ast::{ Assignment, Bag, BagOpExpr, BagOperator, Between, BinOp, BinOpKind, Call, CallAgg, CallArg, CallArgNamed, CaseSensitivity, CreateIndex, CreateTable, Ddl, DdlOp, Delete, Dml, DmlOp, - DropIndex, DropTable, Expr, FromClause, FromLet, FromLetKind, GroupByExpr, GroupKey, + DropIndex, DropTable, Exclusion, Expr, FromClause, FromLet, FromLetKind, GroupByExpr, GroupKey, GroupingStrategy, Insert, InsertValue, Item, Join, JoinKind, JoinSpec, Like, List, Lit, NodeId, NullOrderingSpec, OnConflict, OrderByExpr, OrderingSpec, Path, PathStep, ProjectExpr, Projection, ProjectionKind, Query, QuerySet, Remove, SearchedCase, Select, Set, SetQuantifier, @@ -810,6 +810,10 @@ impl<'a, 'ast> Visitor<'ast> for AstToLogical<'a> { Traverse::Continue } + fn enter_exclusion(&mut self, _exclusion: &'ast Exclusion) -> Traverse { + not_yet_implemented_fault!(self, "EXCLUDE"); + } + fn enter_select(&mut self, select: &'ast Select) -> Traverse { if select.having.is_some() && select.group_by.is_none() { self.errors.push(AstTransformError::HavingWithoutGroupBy); diff --git a/partiql-parser/src/lexer.rs b/partiql-parser/src/lexer.rs index e0235a66..8350d1f1 100644 --- a/partiql-parser/src/lexer.rs +++ b/partiql-parser/src/lexer.rs @@ -545,6 +545,8 @@ pub enum Token<'input> { Escape, #[regex("(?i:Except)")] Except, + #[regex("(?i:Exclude)")] + Exclude, #[regex("(?i:False)")] False, #[regex("(?i:First)")] @@ -776,6 +778,7 @@ impl<'input> fmt::Display for Token<'input> { | Token::End | Token::Escape | Token::Except + | Token::Exclude | Token::False | Token::First | Token::For diff --git a/partiql-parser/src/parse/partiql.lalrpop b/partiql-parser/src/parse/partiql.lalrpop index a57a7d2b..4e28222e 100644 --- a/partiql-parser/src/parse/partiql.lalrpop +++ b/partiql-parser/src/parse/partiql.lalrpop @@ -182,6 +182,7 @@ SfwQuery: ast::AstNode = { SfwClauses: ast::AstNode = { + @@ -189,6 +190,7 @@ SfwClauses: ast::AstNode = { => { state.node(ast::Select { project, + exclude, from, from_let: None, where_clause, @@ -206,9 +208,11 @@ FwsClauses: ast::AstNode = { + => { state.node(ast::Select { project, + exclude, from: Some(from), from_let: None, where_clause, @@ -255,6 +259,13 @@ Projection: ast::AstNode = { }, } +// ------------------------------------------------------------------------------ // +// Exclude // +// ------------------------------------------------------------------------------ // +ExcludeClause: ast::AstNode = { + "EXCLUDE" > => state.node(ast::Exclusion {items}, lo..hi), +} + // ------------------------------------------------------------------------------ // // FROM // // ------------------------------------------------------------------------------ // @@ -1121,22 +1132,60 @@ PathExprVarRef: ast::Expr = { } VarRefExpr: ast::Expr = { - => ast::Expr::VarRef(state.node(ast::VarRef { + => ast::Expr::VarRef(varref), +} + +VarRef: ast::AstNode = { + => state.node(ast::VarRef { name: ast::SymbolPrimitive { value: ident.to_owned(), case: ast::CaseSensitivity::CaseInsensitive }, qualifier: ast::ScopeQualifier::Unqualified - }, lo..hi)), - => ast::Expr::VarRef(state.node(ast::VarRef { + }, lo..hi), + => state.node(ast::VarRef { name: ast::SymbolPrimitive { value: ident.to_owned(), case: ast::CaseSensitivity::CaseSensitive }, qualifier: ast::ScopeQualifier::Unqualified - }, lo..hi)), - => ast::Expr::VarRef(state.node(ast::VarRef { + }, lo..hi), + => state.node(ast::VarRef { name: ast::SymbolPrimitive { value: ident.to_owned(), case: ast::CaseSensitivity::CaseInsensitive }, qualifier: ast::ScopeQualifier::Unqualified - }, lo..hi)), - => ast::Expr::VarRef(state.node(ast::VarRef { + }, lo..hi), + => state.node(ast::VarRef { name: ast::SymbolPrimitive { value: ident.to_owned(), case: ast::CaseSensitivity::CaseSensitive }, qualifier: ast::ScopeQualifier::Unqualified - },lo..hi)), + },lo..hi), +} + +ExcludePath: ast::AstNode = { + => state.node(ast::ExcludePath { root, steps },lo..hi), +} + +ExcludePathSteps: Vec = { + => { + let mut steps = path; + steps.push(step); + steps + }, + => { + vec![step] + }, +} + +ExcludePathStep: ast::ExcludePathStep = { + "." => { + ast::ExcludePathStep::PathProject( state.node(s, lo..hi) ) + }, + "[" "*" "]" => { + ast::ExcludePathStep::PathForEach + }, + "." "*" => { + ast::ExcludePathStep::PathUnpivot + }, + "[" "]" => { + ast::ExcludePathStep::PathIndex( state.node(l, lo..hi) ) + }, + "[" "]" => { + let sym = ast::SymbolPrimitive { value: s.to_string(), case: ast::CaseSensitivity::CaseSensitive }; + ast::ExcludePathStep::PathProject( state.node(sym, lo..hi) ) + }, } // ------------------------------------------------------------------------------ // @@ -1392,6 +1441,7 @@ extern { "DATE" => lexer::Token::Date, "DESC" => lexer::Token::Desc, "DISTINCT" => lexer::Token::Distinct, + "EXCLUDE" => lexer::Token::Exclude, "ELSE" => lexer::Token::Else, "END" => lexer::Token::End, "ESCAPE" => lexer::Token::Escape, diff --git a/partiql-parser/src/preprocessor.rs b/partiql-parser/src/preprocessor.rs index 1c3aea07..c17e3bc9 100644 --- a/partiql-parser/src/preprocessor.rs +++ b/partiql-parser/src/preprocessor.rs @@ -489,9 +489,9 @@ where /// /// * `tok` - The current [`Token`] being considered for matching. /// * `is_nested` - Whether the preprocessor is considering [`Tokens`] inside a nested expression - /// (i.e., inside parens). + /// (i.e., inside parens). /// * `is_init_arg` - Whether this is the first argument being considered for the function expression's - /// parameters. + /// parameters. /// * `matchers` - A slice of the remaining arguments for a single pattern for the function expression. #[allow(clippy::only_used_in_recursion)] fn match_arg( diff --git a/partiql/tests/pretty.rs b/partiql/tests/pretty.rs index ab4ec023..ab3fddbb 100644 --- a/partiql/tests/pretty.rs +++ b/partiql/tests/pretty.rs @@ -168,3 +168,104 @@ fn pretty_pivot() { ", ); } + +#[test] +fn pretty_exclude() { + pretty_print_test( + "pretty_exclude_1", + " + SELECT * EXCLUDE c.ssn, c.address.street FROM [{ + 'name': 'Alan', + 'custId': 1, + 'address': { + 'city': 'Seattle', + 'zipcode': 98109, + 'street': '123 Seaplane Dr.' + }, + 'ssn': 123456789 + }] AS c + ", + ); + pretty_print_test( + "pretty_exclude_2", + " + SELECT * EXCLUDE t.a.b.c[0], t.a.b.c[1].field + FROM [{ + 'a': { + 'b': { + 'c': [ + { + 'field': 0 -- c[0] + }, + { + 'field': 1 -- c[1] + }, + { + 'field': 2 -- c[2] + } + ] + } + }, + 'foo': 'bar' + }] AS t + ", + ); + pretty_print_test( + "pretty_exclude_3", + " + SELECT * + EXCLUDE + t.a.b.c[*].field_x + FROM [{ + 'a': { + 'b': { + 'c': [ + { -- c[0] + 'field_x': 0, + 'field_y': 0 + }, + { -- c[1] + 'field_x': 1, + 'field_y': 1 + }, + { -- c[2] + 'field_x': 2, + 'field_y': 2 + } + ] + } + }, + 'foo': 'bar' + }] AS t + ", + ); + pretty_print_test( + "pretty_exclude_4", + " + SELECT * + EXCLUDE + t.a.b.c[*].* + FROM [{ + 'a': { + 'b': { + 'c': [ + { -- c[0] + 'field_x': 0, + 'field_y': 0 + }, + { -- c[1] + 'field_x': 1, + 'field_y': 1 + }, + { -- c[2] + 'field_x': 2, + 'field_y': 2 + } + ] + } + }, + 'foo': 'bar' + }] AS t + ", + ); +} diff --git a/partiql/tests/snapshots/pretty__pretty_exclude_1.snap b/partiql/tests/snapshots/pretty__pretty_exclude_1.snap new file mode 100644 index 00000000..561fda27 --- /dev/null +++ b/partiql/tests/snapshots/pretty__pretty_exclude_1.snap @@ -0,0 +1,110 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== + + SELECT * EXCLUDE c.ssn, c.address.street FROM [{ + 'name': 'Alan', + 'custId': 1, + 'address': { + 'city': 'Seattle', + 'zipcode': 98109, + 'street': '123 Seaplane Dr.' + }, + 'ssn': 123456789 + }] AS c + +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT * EXCLUDE c.ssn, c.address.street FROM [ { 'name': 'Alan', 'custId': 1, 'address': { 'city': 'Seattle', 'zipcode': 98109, 'street': '123 Seaplane Dr.' }, 'ssn': 123456789 } + ] AS c + +------------------------------------------------------------------------------------------------------------------------ +SELECT * EXCLUDE c.ssn, c.address.street FROM [ + { + 'name': 'Alan', + 'custId': 1, + 'address': { 'city': 'Seattle', 'zipcode': 98109, 'street': '123 Seaplane Dr.' }, + 'ssn': 123456789 + } + ] AS c + +-------------------------------------------------------------------------------- +SELECT * EXCLUDE c.ssn, c.address.street FROM [ + { + 'name': 'Alan', + 'custId': 1, + 'address': { + 'city': 'Seattle', + 'zipcode': 98109, + 'street': '123 Seaplane Dr.' + }, + 'ssn': 123456789 + } + ] AS c + +---------------------------------------- +SELECT * EXCLUDE c.ssn, c.address.street +FROM [ + { + 'name': 'Alan', + 'custId': 1, + 'address': { + 'city': 'Seattle', + 'zipcode': 98109, + 'street': '123 Seaplane Dr.' + }, + 'ssn': 123456789 + } + ] AS c + +------------------------------ +SELECT * EXCLUDE c.ssn, + c.address.street FROM [ + { + 'name': 'Alan', + 'custId': 1, + 'address': { + 'city': 'Seattle', + 'zipcode': 98109, + 'street': '123 Seaplane Dr.' + }, + 'ssn': 123456789 + } + ] AS c + +-------------------- +SELECT * +EXCLUDE c.ssn, + c.address.street +FROM [ + { + 'name': 'Alan', + 'custId': 1, + 'address': { + 'city': 'Seattle', + 'zipcode': 98109, + 'street': '123 Seaplane Dr.' + }, + 'ssn': 123456789 + } + ] AS c + +---------- +SELECT * +EXCLUDE c.ssn, + c.address.street +FROM [ + { + 'name': 'Alan', + 'custId': 1, + 'address': { + 'city': 'Seattle', + 'zipcode': 98109, + 'street': '123 Seaplane Dr.' + }, + 'ssn': 123456789 + } + ] AS c diff --git a/partiql/tests/snapshots/pretty__pretty_exclude_2.snap b/partiql/tests/snapshots/pretty__pretty_exclude_2.snap new file mode 100644 index 00000000..22641bcc --- /dev/null +++ b/partiql/tests/snapshots/pretty__pretty_exclude_2.snap @@ -0,0 +1,127 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== + + SELECT * EXCLUDE t.a.b.c[0], t.a.b.c[1].field + FROM [{ + 'a': { + 'b': { + 'c': [ + { + 'field': 0 -- c[0] + }, + { + 'field': 1 -- c[1] + }, + { + 'field': 2 -- c[2] + } + ] + } + }, + 'foo': 'bar' + }] AS t + +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT * EXCLUDE t.a.b.c[0], t.a.b.c[1].field FROM [ { 'a': { 'b': { 'c': [ { 'field': 0 }, { 'field': 1 }, { 'field': 2 } ] } }, 'foo': 'bar' } ] AS t + +------------------------------------------------------------------------------------------------------------------------ +SELECT * EXCLUDE t.a.b.c[0], t.a.b.c[1].field FROM [ + { 'a': { 'b': { 'c': [ { 'field': 0 }, { 'field': 1 }, { 'field': 2 } ] } }, 'foo': 'bar' } + ] AS t + +-------------------------------------------------------------------------------- +SELECT * EXCLUDE t.a.b.c[0], t.a.b.c[1].field FROM [ + { + 'a': { 'b': { 'c': [ { 'field': 0 }, { 'field': 1 }, { 'field': 2 } ] } }, + 'foo': 'bar' + } + ] AS t + +---------------------------------------- +SELECT * EXCLUDE t.a.b.c[0], + t.a.b.c[1].field FROM [ + { + 'a': { + 'b': { + 'c': [ + { 'field': 0 }, + { 'field': 1 }, + { 'field': 2 } + ] + } + }, + 'foo': 'bar' + } + ] AS t + +------------------------------ +SELECT * EXCLUDE t.a.b.c[0], + t.a.b.c[1].field FROM [ + { + 'a': { + 'b': { + 'c': [ + { 'field': 0 }, + { 'field': 1 }, + { 'field': 2 } + ] + } + }, + 'foo': 'bar' + } + ] AS t + +-------------------- +SELECT * +EXCLUDE t.a.b.c[0], + t.a.b.c[1].field +FROM [ + { + 'a': { + 'b': { + 'c': [ + { + 'field': 0 + }, + { + 'field': 1 + }, + { + 'field': 2 + } + ] + } + }, + 'foo': 'bar' + } + ] AS t + +---------- +SELECT * +EXCLUDE t.a.b.c[0], + t.a.b.c[1].field +FROM [ + { + 'a': { + 'b': { + 'c': [ + { + 'field': 0 + }, + { + 'field': 1 + }, + { + 'field': 2 + } + ] + } + }, + 'foo': 'bar' + } + ] AS t diff --git a/partiql/tests/snapshots/pretty__pretty_exclude_3.snap b/partiql/tests/snapshots/pretty__pretty_exclude_3.snap new file mode 100644 index 00000000..c0ff4c88 --- /dev/null +++ b/partiql/tests/snapshots/pretty__pretty_exclude_3.snap @@ -0,0 +1,164 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== + + SELECT * + EXCLUDE + t.a.b.c[*].field_x + FROM [{ + 'a': { + 'b': { + 'c': [ + { -- c[0] + 'field_x': 0, + 'field_y': 0 + }, + { -- c[1] + 'field_x': 1, + 'field_y': 1 + }, + { -- c[2] + 'field_x': 2, + 'field_y': 2 + } + ] + } + }, + 'foo': 'bar' + }] AS t + +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT * EXCLUDE t.a.b.c[*].field_x FROM [ + { 'a': { 'b': { 'c': [ { 'field_x': 0, 'field_y': 0 }, { 'field_x': 1, 'field_y': 1 }, { 'field_x': 2, 'field_y': 2 } ] } }, 'foo': 'bar' } + ] AS t + +------------------------------------------------------------------------------------------------------------------------ +SELECT * EXCLUDE t.a.b.c[*].field_x FROM [ + { + 'a': { + 'b': { 'c': [ { 'field_x': 0, 'field_y': 0 }, { 'field_x': 1, 'field_y': 1 }, { 'field_x': 2, 'field_y': 2 } ] } + }, + 'foo': 'bar' + } + ] AS t + +-------------------------------------------------------------------------------- +SELECT * EXCLUDE t.a.b.c[*].field_x FROM [ + { + 'a': { + 'b': { + 'c': [ + { 'field_x': 0, 'field_y': 0 }, + { 'field_x': 1, 'field_y': 1 }, + { 'field_x': 2, 'field_y': 2 } + ] + } + }, + 'foo': 'bar' + } + ] AS t + +---------------------------------------- +SELECT * EXCLUDE t.a.b.c[*].field_x +FROM [ + { + 'a': { + 'b': { + 'c': [ + { 'field_x': 0, 'field_y': 0 + }, + { 'field_x': 1, 'field_y': 1 + }, + { 'field_x': 2, 'field_y': 2 + } + ] + } + }, + 'foo': 'bar' + } + ] AS t + +------------------------------ +SELECT * +EXCLUDE t.a.b.c[*].field_x +FROM [ + { + 'a': { + 'b': { + 'c': [ + { + 'field_x': 0, + 'field_y': 0 + }, + { + 'field_x': 1, + 'field_y': 1 + }, + { + 'field_x': 2, + 'field_y': 2 + } + ] + } + }, + 'foo': 'bar' + } + ] AS t + +-------------------- +SELECT * +EXCLUDE t.a.b.c[*].field_x +FROM [ + { + 'a': { + 'b': { + 'c': [ + { + 'field_x': 0, + 'field_y': 0 + }, + { + 'field_x': 1, + 'field_y': 1 + }, + { + 'field_x': 2, + 'field_y': 2 + } + ] + } + }, + 'foo': 'bar' + } + ] AS t + +---------- +SELECT * +EXCLUDE t.a.b.c[*].field_x +FROM [ + { + 'a': { + 'b': { + 'c': [ + { + 'field_x': 0, + 'field_y': 0 + }, + { + 'field_x': 1, + 'field_y': 1 + }, + { + 'field_x': 2, + 'field_y': 2 + } + ] + } + }, + 'foo': 'bar' + } + ] AS t diff --git a/partiql/tests/snapshots/pretty__pretty_exclude_4.snap b/partiql/tests/snapshots/pretty__pretty_exclude_4.snap new file mode 100644 index 00000000..729de7f2 --- /dev/null +++ b/partiql/tests/snapshots/pretty__pretty_exclude_4.snap @@ -0,0 +1,161 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== + + SELECT * + EXCLUDE + t.a.b.c[*].* + FROM [{ + 'a': { + 'b': { + 'c': [ + { -- c[0] + 'field_x': 0, + 'field_y': 0 + }, + { -- c[1] + 'field_x': 1, + 'field_y': 1 + }, + { -- c[2] + 'field_x': 2, + 'field_y': 2 + } + ] + } + }, + 'foo': 'bar' + }] AS t + +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT * EXCLUDE t.a.b.c[*].* FROM [ { 'a': { 'b': { 'c': [ { 'field_x': 0, 'field_y': 0 }, { 'field_x': 1, 'field_y': 1 }, { 'field_x': 2, 'field_y': 2 } ] } }, 'foo': 'bar' } + ] AS t + +------------------------------------------------------------------------------------------------------------------------ +SELECT * EXCLUDE t.a.b.c[*].* FROM [ + { + 'a': { + 'b': { 'c': [ { 'field_x': 0, 'field_y': 0 }, { 'field_x': 1, 'field_y': 1 }, { 'field_x': 2, 'field_y': 2 } ] } + }, + 'foo': 'bar' + } + ] AS t + +-------------------------------------------------------------------------------- +SELECT * EXCLUDE t.a.b.c[*].* FROM [ + { + 'a': { + 'b': { + 'c': [ + { 'field_x': 0, 'field_y': 0 }, + { 'field_x': 1, 'field_y': 1 }, + { 'field_x': 2, 'field_y': 2 } + ] + } + }, + 'foo': 'bar' + } + ] AS t + +---------------------------------------- +SELECT * EXCLUDE t.a.b.c[*].* FROM [ + { + 'a': { + 'b': { + 'c': [ + { 'field_x': 0, 'field_y': 0 + }, + { 'field_x': 1, 'field_y': 1 + }, + { 'field_x': 2, 'field_y': 2 + } + ] + } + }, + 'foo': 'bar' + } + ] AS t + +------------------------------ +SELECT * EXCLUDE t.a.b.c[*].* +FROM [ + { + 'a': { + 'b': { + 'c': [ + { + 'field_x': 0, + 'field_y': 0 + }, + { + 'field_x': 1, + 'field_y': 1 + }, + { + 'field_x': 2, + 'field_y': 2 + } + ] + } + }, + 'foo': 'bar' + } + ] AS t + +-------------------- +SELECT * +EXCLUDE t.a.b.c[*].* +FROM [ + { + 'a': { + 'b': { + 'c': [ + { + 'field_x': 0, + 'field_y': 0 + }, + { + 'field_x': 1, + 'field_y': 1 + }, + { + 'field_x': 2, + 'field_y': 2 + } + ] + } + }, + 'foo': 'bar' + } + ] AS t + +---------- +SELECT * +EXCLUDE t.a.b.c[*].* +FROM [ + { + 'a': { + 'b': { + 'c': [ + { + 'field_x': 0, + 'field_y': 0 + }, + { + 'field_x': 1, + 'field_y': 1 + }, + { + 'field_x': 2, + 'field_y': 2 + } + ] + } + }, + 'foo': 'bar' + } + ] AS t