surrealdb_core/sql/statements/define/
model.rs

1use crate::ctx::Context;
2use crate::dbs::Options;
3use crate::doc::CursorDoc;
4use crate::err::Error;
5use crate::iam::{Action, ResourceKind};
6use crate::sql::statements::info::InfoStructure;
7use crate::sql::{
8	fmt::{is_pretty, pretty_indent},
9	Base, Ident, Object, Permission, Strand, Value,
10};
11use derive::Store;
12use revision::revisioned;
13use serde::{Deserialize, Serialize};
14use std::fmt::{self, Write};
15
16#[revisioned(revision = 2)]
17#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
18#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
19#[non_exhaustive]
20pub struct DefineModelStatement {
21	pub hash: String,
22	pub name: Ident,
23	pub version: String,
24	pub comment: Option<Strand>,
25	pub permissions: Permission,
26	#[revision(start = 2)]
27	pub if_not_exists: bool,
28}
29
30impl fmt::Display for DefineModelStatement {
31	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32		write!(f, "DEFINE MODEL")?;
33		if self.if_not_exists {
34			write!(f, " IF NOT EXISTS")?
35		}
36		write!(f, " ml::{}<{}>", self.name, self.version)?;
37		if let Some(comment) = self.comment.as_ref() {
38			write!(f, " COMMENT {}", comment)?;
39		}
40		let _indent = if is_pretty() {
41			Some(pretty_indent())
42		} else {
43			f.write_char(' ')?;
44			None
45		};
46		write!(f, "PERMISSIONS {}", self.permissions)?;
47		Ok(())
48	}
49}
50
51impl DefineModelStatement {
52	/// Process this type returning a computed simple Value
53	pub(crate) async fn compute(
54		&self,
55		ctx: &Context<'_>,
56		opt: &Options,
57		_doc: Option<&CursorDoc<'_>>,
58	) -> Result<Value, Error> {
59		// Allowed to run?
60		opt.is_allowed(Action::Edit, ResourceKind::Model, &Base::Db)?;
61		// Claim transaction
62		let mut run = ctx.tx_lock().await;
63		// Clear the cache
64		run.clear_cache();
65		// Check if model already exists
66		if run.get_db_model(opt.ns()?, opt.db()?, &self.name, &self.version).await.is_ok() {
67			if self.if_not_exists {
68				return Ok(Value::None);
69			} else {
70				return Err(Error::MlAlreadyExists {
71					value: self.name.to_string(),
72				});
73			}
74		}
75		// Process the statement
76		let key = crate::key::database::ml::new(opt.ns()?, opt.db()?, &self.name, &self.version);
77		run.add_ns(opt.ns()?, opt.strict).await?;
78		run.add_db(opt.ns()?, opt.db()?, opt.strict).await?;
79		run.set(
80			key,
81			DefineModelStatement {
82				// Don't persist the "IF NOT EXISTS" clause to schema
83				if_not_exists: false,
84				..self.clone()
85			},
86		)
87		.await?;
88		// Store the model file
89		// TODO
90		// Ok all good
91		Ok(Value::None)
92	}
93}
94
95impl InfoStructure for DefineModelStatement {
96	fn structure(self) -> Value {
97		let Self {
98			name,
99			version,
100			comment,
101			permissions,
102			..
103		} = self;
104		let mut acc = Object::default();
105
106		acc.insert("name".to_string(), name.structure());
107
108		acc.insert("version".to_string(), version.into());
109
110		if let Some(comment) = comment {
111			acc.insert("comment".to_string(), comment.into());
112		}
113
114		acc.insert("permissions".to_string(), permissions.structure());
115
116		Value::Object(acc)
117	}
118}