1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use crate::begin_batch::BeginBatch;
use crate::common::{FQName, Identifier, RelationElement};
use itertools::Itertools;
use std::fmt::{Display, Formatter};

/// the data for a delete statement.
#[derive(PartialEq, Debug, Clone)]
pub struct Delete {
    /// if set the statement starts with `BEGIN BATCH`
    pub begin_batch: Option<BeginBatch>,
    /// an optional list of columns to delete
    pub columns: Vec<IndexedColumn>,
    /// the table to delete from
    pub table_name: FQName,
    /// an optional timestamp to use for the deletion.
    pub timestamp: Option<u64>,
    /// the were clause for the delete.
    pub where_clause: Vec<RelationElement>,
    /// if present a list of key,values for the `IF` clause
    pub if_clause: Vec<RelationElement>,
    /// if true and if_clause is NONE then `IF EXISTS` is added
    pub if_exists: bool,
}

impl Display for Delete {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}DELETE {}FROM {}{} WHERE {}{}",
            self.begin_batch
                .as_ref()
                .map_or("".to_string(), |x| x.to_string()),
            {
                let mut str = "".to_string();
                if !self.columns.is_empty() {
                    str = self.columns.iter().join(", ");
                    str.push(' ');
                }
                str
            },
            self.table_name,
            self.timestamp
                .as_ref()
                .map_or("".to_string(), |x| format!(" USING TIMESTAMP {}", x)),
            self.where_clause.iter().join(" AND "),
            if !self.if_clause.is_empty() {
                format!(" IF {}", self.if_clause.iter().join(" AND "))
            } else if self.if_exists {
                " IF EXISTS".to_string()
            } else {
                "".to_string()
            }
        )
    }
}

/// Defines an indexed column.  Indexed columns comprise a column name and an optional index into
/// the column.  This is expressed as `column[idx]`
#[derive(PartialEq, Debug, Clone)]
pub struct IndexedColumn {
    /// the column name
    pub column: Identifier,
    /// the optional index in to the column
    pub idx: Option<String>,
}

impl Display for IndexedColumn {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match &self.idx {
            Some(x) => write!(f, "{}[{}]", self.column, x),
            None => write!(f, "{}", self.column),
        }
    }
}