surrealdb_core/sql/statements/remove/
table.rs

1use crate::ctx::Context;
2use crate::dbs::Options;
3use crate::err::Error;
4use crate::iam::{Action, ResourceKind};
5use crate::sql::statements::define::DefineTableStatement;
6use crate::sql::{Base, Ident, Value};
7
8use revision::revisioned;
9use serde::{Deserialize, Serialize};
10use std::fmt::{self, Display, Formatter};
11use uuid::Uuid;
12
13#[revisioned(revision = 3)]
14#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
15#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
16#[non_exhaustive]
17pub struct RemoveTableStatement {
18	pub name: Ident,
19	#[revision(start = 2)]
20	pub if_exists: bool,
21	#[revision(start = 3)]
22	pub expunge: bool,
23}
24
25impl RemoveTableStatement {
26	/// Process this type returning a computed simple Value
27	pub(crate) async fn compute(&self, ctx: &Context, opt: &Options) -> Result<Value, Error> {
28		let future = async {
29			// Allowed to run?
30			opt.is_allowed(Action::Edit, ResourceKind::Table, &Base::Db)?;
31			// Get the NS and DB
32			let (ns, db) = opt.ns_db()?;
33			// Get the transaction
34			let txn = ctx.tx();
35			// Remove the index stores
36			ctx.get_index_stores()
37				.table_removed(ctx.get_index_builder(), &txn, ns, db, &self.name)
38				.await?;
39			// Get the defined table
40			let tb = txn.get_tb(ns, db, &self.name).await?;
41			// Get the foreign tables
42			let fts = txn.all_tb_views(ns, db, &self.name).await?;
43			// Delete the definition
44			let key = crate::key::database::tb::new(ns, db, &self.name);
45			match self.expunge {
46				true => txn.clr(key).await?,
47				false => txn.del(key).await?,
48			};
49			// Remove the resource data
50			let key = crate::key::table::all::new(ns, db, &self.name);
51			match self.expunge {
52				true => txn.clrp(key).await?,
53				false => txn.delp(key).await?,
54			};
55			// Process each attached foreign table
56			for ft in fts.iter() {
57				// Refresh the table cache
58				let key = crate::key::database::tb::new(ns, db, &ft.name);
59				let tb = txn.get_tb(ns, db, &ft.name).await?;
60				txn.set(
61					key,
62					revision::to_vec(&DefineTableStatement {
63						view: None,
64						..tb.as_ref().clone()
65					})?,
66					None,
67				)
68				.await?;
69				// Clear the cache
70				if let Some(cache) = ctx.get_cache() {
71					cache.clear_tb(ns, db, &ft.name);
72				}
73			}
74			// Check if this is a foreign table
75			if let Some(view) = &tb.view {
76				// Process each foreign table
77				for ft in view.what.0.iter() {
78					// Save the view config
79					let key = crate::key::table::ft::new(ns, db, ft, &self.name);
80					txn.del(key).await?;
81					// Refresh the table cache for foreign tables
82					let key = crate::key::database::tb::new(ns, db, ft);
83					let tb = txn.get_tb(ns, db, ft).await?;
84					txn.set(
85						key,
86						revision::to_vec(&DefineTableStatement {
87							cache_tables_ts: Uuid::now_v7(),
88							..tb.as_ref().clone()
89						})?,
90						None,
91					)
92					.await?;
93				}
94			}
95			// Clear the cache
96			if let Some(cache) = ctx.get_cache() {
97				cache.clear_tb(ns, db, &self.name);
98			}
99			// Clear the cache
100			txn.clear();
101			// Ok all good
102			Ok(Value::None)
103		}
104		.await;
105		match future {
106			Err(Error::TbNotFound {
107				..
108			}) if self.if_exists => Ok(Value::None),
109			v => v,
110		}
111	}
112}
113
114impl Display for RemoveTableStatement {
115	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
116		write!(f, "REMOVE TABLE")?;
117		if self.if_exists {
118			write!(f, " IF EXISTS")?
119		}
120		write!(f, " {}", self.name)?;
121		Ok(())
122	}
123}