surrealdb_core/sql/statements/define/
field.rs1use 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::statements::DefineTableStatement;
8use crate::sql::{
9 fmt::is_pretty, fmt::pretty_indent, Base, Ident, Idiom, Kind, Permissions, Strand, Value,
10};
11use crate::sql::{Object, Part};
12use crate::sql::{Relation, TableType};
13use derive::Store;
14use revision::revisioned;
15use serde::{Deserialize, Serialize};
16use std::fmt::{self, Display, Write};
17
18#[revisioned(revision = 3)]
19#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
20#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
21#[non_exhaustive]
22pub struct DefineFieldStatement {
23 pub name: Idiom,
24 pub what: Ident,
25 pub flex: bool,
26 pub kind: Option<Kind>,
27 #[revision(start = 2)]
28 pub readonly: bool,
29 pub value: Option<Value>,
30 pub assert: Option<Value>,
31 pub default: Option<Value>,
32 pub permissions: Permissions,
33 pub comment: Option<Strand>,
34 #[revision(start = 3)]
35 pub if_not_exists: bool,
36}
37
38impl DefineFieldStatement {
39 pub(crate) async fn compute(
41 &self,
42 ctx: &Context<'_>,
43 opt: &Options,
44 _doc: Option<&CursorDoc<'_>>,
45 ) -> Result<Value, Error> {
46 opt.is_allowed(Action::Edit, ResourceKind::Field, &Base::Db)?;
48 let mut run = ctx.tx_lock().await;
50 run.clear_cache();
52 let fd = self.name.to_string();
54 if run.get_tb_field(opt.ns()?, opt.db()?, &self.what, &fd).await.is_ok() {
55 if self.if_not_exists {
56 return Ok(Value::None);
57 } else {
58 return Err(Error::FdAlreadyExists {
59 value: fd,
60 });
61 }
62 }
63 run.add_ns(opt.ns()?, opt.strict).await?;
65 run.add_db(opt.ns()?, opt.db()?, opt.strict).await?;
66
67 let tb = run.add_tb(opt.ns()?, opt.db()?, &self.what, opt.strict).await?;
68 let key = crate::key::table::fd::new(opt.ns()?, opt.db()?, &self.what, &fd);
69 run.set(
70 key,
71 DefineFieldStatement {
72 if_not_exists: false,
73 ..self.clone()
74 },
75 )
76 .await?;
77
78 let fields = run.all_tb_fields(opt.ns()?, opt.db()?, &self.what).await.ok();
80
81 if let Some(mut cur_kind) = self.kind.as_ref().and_then(|x| x.inner_kind()) {
83 let mut name = self.name.clone();
84 loop {
85 let new_kind = cur_kind.inner_kind();
86 name.0.push(Part::All);
87
88 let fd = name.to_string();
89 let key = crate::key::table::fd::new(opt.ns()?, opt.db()?, &self.what, &fd);
90 run.add_ns(opt.ns()?, opt.strict).await?;
91 run.add_db(opt.ns()?, opt.db()?, opt.strict).await?;
92
93 let statement = if let Some(existing) =
95 fields.as_ref().and_then(|x| x.iter().find(|x| x.name == name))
96 {
97 DefineFieldStatement {
98 kind: Some(cur_kind),
99 if_not_exists: false,
100 ..existing.clone()
101 }
102 } else {
103 DefineFieldStatement {
104 name: name.clone(),
105 what: self.what.clone(),
106 flex: self.flex,
107 kind: Some(cur_kind),
108 ..Default::default()
109 }
110 };
111
112 run.set(key, statement).await?;
113
114 if let Some(new_kind) = new_kind {
115 cur_kind = new_kind;
116 } else {
117 break;
118 }
119 }
120 }
121
122 let new_tb = match (fd.as_str(), tb.kind.clone(), self.kind.clone()) {
123 ("in", TableType::Relation(rel), Some(dk)) => {
124 if !matches!(dk, Kind::Record(_)) {
125 return Err(Error::Thrown("in field on a relation must be a record".into()));
126 };
127 if rel.from.as_ref() != Some(&dk) {
128 Some(DefineTableStatement {
129 kind: TableType::Relation(Relation {
130 from: Some(dk),
131 ..rel
132 }),
133 ..tb
134 })
135 } else {
136 None
137 }
138 }
139 ("out", TableType::Relation(rel), Some(dk)) => {
140 if !matches!(dk, Kind::Record(_)) {
141 return Err(Error::Thrown("out field on a relation must be a record".into()));
142 };
143 if rel.to.as_ref() != Some(&dk) {
144 Some(DefineTableStatement {
145 kind: TableType::Relation(Relation {
146 to: Some(dk),
147 ..rel
148 }),
149 ..tb
150 })
151 } else {
152 None
153 }
154 }
155 _ => None,
156 };
157 if let Some(tb) = new_tb {
158 let key = crate::key::database::tb::new(opt.ns()?, opt.db()?, &self.what);
159 run.set(key, &tb).await?;
160 let key = crate::key::table::ft::prefix(opt.ns()?, opt.db()?, &self.what);
161 run.clr(key).await?;
162 }
163
164 let key = crate::key::table::fd::prefix(opt.ns()?, opt.db()?, &self.what);
166 run.clr(key).await?;
167 Ok(Value::None)
169 }
170}
171
172impl Display for DefineFieldStatement {
173 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174 write!(f, "DEFINE FIELD")?;
175 if self.if_not_exists {
176 write!(f, " IF NOT EXISTS")?
177 }
178 write!(f, " {} ON {}", self.name, self.what)?;
179 if self.flex {
180 write!(f, " FLEXIBLE")?
181 }
182 if let Some(ref v) = self.kind {
183 write!(f, " TYPE {v}")?
184 }
185 if let Some(ref v) = self.default {
186 write!(f, " DEFAULT {v}")?
187 }
188 if self.readonly {
189 write!(f, " READONLY")?
190 }
191 if let Some(ref v) = self.value {
192 write!(f, " VALUE {v}")?
193 }
194 if let Some(ref v) = self.assert {
195 write!(f, " ASSERT {v}")?
196 }
197 if let Some(ref v) = self.comment {
198 write!(f, " COMMENT {v}")?
199 }
200 let _indent = if is_pretty() {
201 Some(pretty_indent())
202 } else {
203 f.write_char(' ')?;
204 None
205 };
206 write!(f, "{}", self.permissions)?;
207 Ok(())
208 }
209}
210
211impl InfoStructure for DefineFieldStatement {
212 fn structure(self) -> Value {
213 let Self {
214 name,
215 what,
216 flex,
217 kind,
218 readonly,
219 value,
220 assert,
221 default,
222 permissions,
223 comment,
224 ..
225 } = self;
226 let mut acc = Object::default();
227
228 acc.insert("name".to_string(), name.structure());
229
230 acc.insert("what".to_string(), what.structure());
231
232 acc.insert("flex".to_string(), flex.into());
233
234 if let Some(kind) = kind {
235 acc.insert("kind".to_string(), kind.structure());
236 }
237
238 acc.insert("readonly".to_string(), readonly.into());
239
240 if let Some(value) = value {
241 acc.insert("value".to_string(), value.structure());
242 }
243
244 if let Some(assert) = assert {
245 acc.insert("assert".to_string(), assert.structure());
246 }
247
248 if let Some(default) = default {
249 acc.insert("default".to_string(), default.structure());
250 }
251
252 acc.insert("permissions".to_string(), permissions.structure());
253
254 if let Some(comment) = comment {
255 acc.insert("comment".to_string(), comment.into());
256 }
257
258 Value::Object(acc)
259 }
260}