diff --git a/rust/parser/pipeline.rs b/rust/parser/pipeline.rs index 24446d3d..2f76d55d 100644 --- a/rust/parser/pipeline.rs +++ b/rust/parser/pipeline.rs @@ -175,8 +175,9 @@ fn visit_clause_insert(node: Node<'_>) -> Insert { .into_children() .skip_expected(Rule::INSERT) .map(|child| match child.as_rule() { - Rule::statement_thing => visit_statement_thing(child), - Rule::statement_assignment => Statement::Assignment(visit_statement_assignment(child)), + Rule::statement_thing => Pattern::Statement(visit_statement_thing(child)), + Rule::statement_assignment => Pattern::Statement(Statement::Assignment(visit_statement_assignment(child))), + Rule::pattern_try => Pattern::Optional(visit_pattern_try(child)), _ => unreachable!( "Unrecognised statement inside insert clause: {:?}", TypeQLError::IllegalGrammar { input: child.as_str().to_owned() } @@ -203,7 +204,18 @@ fn visit_clause_update(node: Node<'_>) -> Update { fn visit_clause_delete(node: Node<'_>) -> Delete { debug_assert_eq!(node.as_rule(), Rule::clause_delete); let span = node.span(); - let deletables = node.into_children().skip_expected(Rule::DELETE).map(visit_statement_deletable).collect(); + let deletables = node + .into_children() + .skip_expected(Rule::DELETE) + .map(|child| match child.as_rule() { + Rule::statement_deletable => visit_statement_deletable(child), + Rule::pattern_try_deletable => visit_pattern_try_deletable(child), + _ => unreachable!( + "Unrecognised statement inside delete clause: {:?}", + TypeQLError::IllegalGrammar { input: child.as_str().to_owned() } + ), + }) + .collect(); Delete::new(span, deletables) } @@ -235,6 +247,24 @@ fn visit_statement_deletable(node: Node<'_>) -> Deletable { Deletable::new(span, kind) } +fn visit_pattern_try_deletable(node: Node<'_>) -> Deletable { + debug_assert_eq!(node.as_rule(), Rule::pattern_try_deletable); + let span = node.span(); + let deletables = node + .into_children() + .skip_expected(Rule::TRY) + .map(|child| match child.as_rule() { + Rule::statement_deletable => visit_statement_deletable(child), + Rule::pattern_try_deletable => visit_pattern_try_deletable(child), + _ => unreachable!( + "Unrecognised statement inside delete clause: {:?}", + TypeQLError::IllegalGrammar { input: child.as_str().to_owned() } + ), + }) + .collect(); + Deletable::new(span, DeletableKind::Optional { deletables }) +} + fn visit_clause_fetch(node: Node<'_>) -> Fetch { debug_assert_eq!(node.as_rule(), Rule::clause_fetch); let span = node.span(); diff --git a/rust/parser/typeql.pest b/rust/parser/typeql.pest index 4bbd7c66..8ce90b37 100644 --- a/rust/parser/typeql.pest +++ b/rust/parser/typeql.pest @@ -29,11 +29,11 @@ query_stage_terminal = { clause_fetch ~ SEMICOLON } clause_match = { MATCH ~ patterns } -clause_insert = { INSERT ~ ( statement_thing ~ SEMICOLON | statement_assignment ~ SEMICOLON )+ } +clause_insert = { INSERT ~ ( ( statement_thing | statement_assignment | pattern_try ) ~ SEMICOLON )+ } clause_put = { PUT ~ ( statement_thing ~ SEMICOLON )+ } clause_update = { UPDATE ~ ( statement_thing ~ SEMICOLON )+ } -clause_delete = { DELETE ~ ( statement_deletable ~ SEMICOLON )+ } +clause_delete = { DELETE ~ ( ( statement_deletable | pattern_try_deletable ) ~ SEMICOLON )+ } // STREAM OPERATORS =========================================================== @@ -123,6 +123,8 @@ statement_deletable = { HAS? ~ var ~ OF ~ var | var } +pattern_try_deletable = { TRY ~ CURLY_OPEN ~ ( statement_deletable ~ SEMICOLON )+ ~ CURLY_CLOSE } + // SINGLE STATEMENTS =========================================================== statement_single = { statement_is | statement_comparison | statement_assignment | statement_in } diff --git a/rust/query/pipeline/stage/delete.rs b/rust/query/pipeline/stage/delete.rs index 9c064b53..6339f143 100644 --- a/rust/query/pipeline/stage/delete.rs +++ b/rust/query/pipeline/stage/delete.rs @@ -93,9 +93,27 @@ pub enum DeletableKind { Has { attribute: Variable, owner: Variable }, Links { players: Relation, relation: Variable }, Concept { variable: Variable }, + Optional { deletables: Vec }, } -impl Pretty for DeletableKind {} +impl Pretty for DeletableKind { + fn fmt(&self, indent_level: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Optional { deletables } => { + writeln!(f, "{} {{", token::Keyword::Try)?; + for deletable in deletables { + indent(indent_level + 1, f)?; + Pretty::fmt(deletable, indent_level + 1, f)?; + writeln!(f, ";")?; + indent(indent_level, f)?; + } + f.write_char('}')?; + Ok(()) + } + _ => write!(f, "{}", self), + } + } +} impl fmt::Display for DeletableKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -107,6 +125,14 @@ impl fmt::Display for DeletableKind { write!(f, "{} {} {} {}", token::Keyword::Links, players, token::Keyword::Of, relation) } Self::Concept { variable } => write!(f, "{}", variable), + Self::Optional { deletables } => { + write!(f, "{} {{ ", token::Keyword::Try)?; + for deletable in deletables { + write!(f, "{}; ", deletable)?; + } + f.write_char('}')?; + Ok(()) + } } } } diff --git a/rust/query/pipeline/stage/insert.rs b/rust/query/pipeline/stage/insert.rs index e07f9549..a041199e 100644 --- a/rust/query/pipeline/stage/insert.rs +++ b/rust/query/pipeline/stage/insert.rs @@ -8,19 +8,19 @@ use std::fmt::{self, Write}; use crate::{ common::{token, Span, Spanned}, + pattern::Pattern, pretty::{indent, Pretty}, - statement::Statement, }; #[derive(Debug, Clone, Eq, PartialEq)] pub struct Insert { pub span: Option, - pub statements: Vec, + pub patterns: Vec, } impl Insert { - pub(crate) fn new(span: Option, statements: Vec) -> Self { - Self { span, statements } + pub(crate) fn new(span: Option, patterns: Vec) -> Self { + Self { span, patterns } } } @@ -33,10 +33,10 @@ impl Spanned for Insert { impl Pretty for Insert { fn fmt(&self, indent_level: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", token::Clause::Insert)?; - for statement in &self.statements { + for pattern in &self.patterns { writeln!(f)?; indent(indent_level, f)?; - Pretty::fmt(statement, indent_level, f)?; + Pretty::fmt(pattern, indent_level, f)?; f.write_char(';')?; } Ok(()) @@ -49,7 +49,7 @@ impl fmt::Display for Insert { Pretty::fmt(self, 0, f) } else { write!(f, "{}", token::Clause::Insert)?; - for statement in &self.statements { + for statement in &self.patterns { write!(f, " {statement};")?; } Ok(())