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			#[cfg(not(target_family = "wasm"))]
37			ctx.get_index_stores()
38				.table_removed(ctx.get_index_builder(), &txn, ns, db, &self.name)
39				.await?;
40			#[cfg(target_family = "wasm")]
41			ctx.get_index_stores().table_removed(&txn, ns, db, &self.name).await?;
42			// Get the defined table
43			let tb = txn.get_tb(ns, db, &self.name).await?;
44			// Get the foreign tables
45			let fts = txn.all_tb_views(ns, db, &self.name).await?;
46			// Delete the definition
47			let key = crate::key::database::tb::new(ns, db, &self.name);
48			match self.expunge {
49				true => txn.clr(key).await?,
50				false => txn.del(key).await?,
51			};
52			// Remove the resource data
53			let key = crate::key::table::all::new(ns, db, &self.name);
54			match self.expunge {
55				true => txn.clrp(key).await?,
56				false => txn.delp(key).await?,
57			};
58			// Process each attached foreign table
59			for ft in fts.iter() {
60				// Refresh the table cache
61				let key = crate::key::database::tb::new(ns, db, &ft.name);
62				let tb = txn.get_tb(ns, db, &ft.name).await?;
63				txn.set(
64					key,
65					revision::to_vec(&DefineTableStatement {
66						view: None,
67						..tb.as_ref().clone()
68					})?,
69					None,
70				)
71				.await?;
72				// Clear the cache
73				if let Some(cache) = ctx.get_cache() {
74					cache.clear_tb(ns, db, &ft.name);
75				}
76			}
77			// Check if this is a foreign table
78			if let Some(view) = &tb.view {
79				// Process each foreign table
80				for ft in view.what.0.iter() {
81					// Save the view config
82					let key = crate::key::table::ft::new(ns, db, ft, &self.name);
83					txn.del(key).await?;
84					// Refresh the table cache for foreign tables
85					let key = crate::key::database::tb::new(ns, db, ft);
86					let tb = txn.get_tb(ns, db, ft).await?;
87					txn.set(
88						key,
89						revision::to_vec(&DefineTableStatement {
90							cache_tables_ts: Uuid::now_v7(),
91							..tb.as_ref().clone()
92						})?,
93						None,
94					)
95					.await?;
96				}
97			}
98			// Clear the cache
99			if let Some(cache) = ctx.get_cache() {
100				cache.clear_tb(ns, db, &self.name);
101			}
102			// Clear the cache
103			txn.clear();
104			// Ok all good
105			Ok(Value::None)
106		}
107		.await;
108		match future {
109			Err(Error::TbNotFound {
110				..
111			}) if self.if_exists => Ok(Value::None),
112			v => v,
113		}
114	}
115}
116
117impl Display for RemoveTableStatement {
118	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
119		write!(f, "REMOVE TABLE")?;
120		if self.if_exists {
121			write!(f, " IF EXISTS")?
122		}
123		write!(f, " {}", self.name)?;
124		Ok(())
125	}
126}