Skip to main content

surrealdb_sql/statements/alter/
table.rs

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