Skip to main content

surql_parser/upstream/sql/statements/alter/
table.rs

1use super::AlterKind;
2use crate::upstream::fmt::{EscapeKwFreeIdent, EscapeKwIdent, QuoteStr};
3use crate::upstream::sql::{ChangeFeed, Permissions, TableType};
4use surrealdb_types::{SqlFormat, ToSql, write_sql};
5#[derive(Clone, Debug, Default, Eq, PartialEq)]
6#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
7/// AST node for `ALTER TABLE`.
8///
9/// Supported operations include (order-insensitive after the table name):
10/// - `TYPE NORMAL | RELATION [IN <from> [OUT <to>]] | ANY`
11/// - `SCHEMAFULL` / `SCHEMALESS`
12/// - `PERMISSIONS ...`
13/// - `CHANGEFEED ...` / `DROP CHANGEFEED`
14/// - `COMMENT <string>` / `DROP COMMENT`
15/// - `COMPACT` (request table keyspace compaction)
16///
17/// Note: `COMPACT` is parsed and preserved on the expression side, however it is
18/// currently not rendered by this node's `ToSql` implementation.
19pub struct AlterTableStatement {
20	pub name: String,
21	pub if_exists: bool,
22	pub schemafull: AlterKind<()>,
23	pub permissions: Option<Permissions>,
24	pub changefeed: AlterKind<ChangeFeed>,
25	pub comment: AlterKind<String>,
26	pub kind: Option<TableType>,
27	/// Request table‑level compaction when true.
28	pub compact: bool,
29}
30impl ToSql for AlterTableStatement {
31	fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
32		write_sql!(f, fmt, "ALTER TABLE");
33		if self.if_exists {
34			write_sql!(f, fmt, " IF EXISTS");
35		}
36		write_sql!(f, fmt, " {}", EscapeKwIdent(&self.name, &["IF"]));
37		if let Some(kind) = &self.kind {
38			write_sql!(f, fmt, " TYPE");
39			match &kind {
40				TableType::Normal => {
41					write_sql!(f, fmt, " NORMAL");
42				}
43				TableType::Relation(rel) => {
44					write_sql!(f, fmt, " RELATION");
45					if !rel.from.is_empty() {
46						f.push_str(" IN ");
47						for (idx, k) in rel.from.iter().enumerate() {
48							if idx != 0 {
49								f.push_str(" | ");
50							}
51							write_sql!(f, fmt, "{}", EscapeKwFreeIdent(k));
52						}
53					}
54					if !rel.to.is_empty() {
55						f.push_str(" OUT ");
56						for (idx, k) in rel.to.iter().enumerate() {
57							if idx != 0 {
58								f.push_str(" | ");
59							}
60							write_sql!(f, fmt, "{}", EscapeKwFreeIdent(k));
61						}
62					}
63				}
64				TableType::Any => {
65					write_sql!(f, fmt, " ANY");
66				}
67			}
68		}
69		match self.schemafull {
70			AlterKind::Set(_) => write_sql!(f, fmt, " SCHEMAFULL"),
71			AlterKind::Drop => write_sql!(f, fmt, " SCHEMALESS"),
72			AlterKind::None => {}
73		}
74		match self.comment {
75			AlterKind::Set(ref comment) => {
76				write_sql!(f, fmt, " COMMENT {}", QuoteStr(comment))
77			}
78			AlterKind::Drop => f.push_str(" DROP COMMENT"),
79			AlterKind::None => {}
80		}
81		match self.changefeed {
82			AlterKind::Set(ref changefeed) => write_sql!(f, fmt, " {}", changefeed),
83			AlterKind::Drop => f.push_str(" DROP CHANGEFEED"),
84			AlterKind::None => {}
85		}
86		if let Some(permissions) = &self.permissions {
87			write_sql!(f, fmt, " {permissions}");
88		}
89		if self.compact {
90			write_sql!(f, fmt, " COMPACT");
91		}
92	}
93}