surrealdb_core/sql/statements/
insert.rs

1use crate::ctx::Context;
2use crate::dbs::{Iterable, Iterator, Options, Statement};
3use crate::doc::CursorDoc;
4use crate::err::Error;
5use crate::sql::paths::IN;
6use crate::sql::paths::OUT;
7use crate::sql::{Data, Id, Output, Table, Thing, Timeout, Value};
8use derive::Store;
9use reblessive::tree::Stk;
10use revision::revisioned;
11use serde::{Deserialize, Serialize};
12use std::fmt;
13
14#[revisioned(revision = 2)]
15#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
16#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
17#[non_exhaustive]
18pub struct InsertStatement {
19	pub into: Option<Value>,
20	pub data: Data,
21	pub ignore: bool,
22	pub update: Option<Data>,
23	pub output: Option<Output>,
24	pub timeout: Option<Timeout>,
25	pub parallel: bool,
26	#[revision(start = 2)]
27	pub relation: bool,
28}
29
30impl InsertStatement {
31	/// Check if we require a writeable transaction
32	pub(crate) fn writeable(&self) -> bool {
33		true
34	}
35	/// Process this type returning a computed simple Value
36	pub(crate) async fn compute(
37		&self,
38		stk: &mut Stk,
39		ctx: &Context<'_>,
40		opt: &Options,
41		doc: Option<&CursorDoc<'_>>,
42	) -> Result<Value, Error> {
43		// Valid options?
44		opt.valid_for_db()?;
45		// Create a new iterator
46		let mut i = Iterator::new();
47		// Ensure futures are stored
48		let opt = &opt.new_with_futures(false).with_projections(false);
49		// Parse the INTO expression
50		let into = match &self.into {
51			None => None,
52			Some(into) => match into.compute(stk, ctx, opt, doc).await? {
53				Value::Table(into) => Some(into),
54				v => {
55					return Err(Error::InsertStatement {
56						value: v.to_string(),
57					})
58				}
59			},
60		};
61		// Parse the data expression
62		match &self.data {
63			// Check if this is a traditional statement
64			Data::ValuesExpression(v) => {
65				for v in v {
66					// Create a new empty base object
67					let mut o = Value::base();
68					// Set each field from the expression
69					for (k, v) in v.iter() {
70						let v = v.compute(stk, ctx, opt, None).await?;
71						o.set(stk, ctx, opt, k, v).await?;
72					}
73					// Specify the new table record id
74					let id = gen_id(&o, &into)?;
75					// Pass the value to the iterator
76					i.ingest(iterable(id, o, self.relation)?)
77				}
78			}
79			// Check if this is a modern statement
80			Data::SingleExpression(v) => {
81				let v = v.compute(stk, ctx, opt, doc).await?;
82				match v {
83					Value::Array(v) => {
84						for v in v {
85							// Specify the new table record id
86							let id = gen_id(&v, &into)?;
87							// Pass the value to the iterator
88							i.ingest(iterable(id, v, self.relation)?)
89						}
90					}
91					Value::Object(_) => {
92						// Specify the new table record id
93						let id = gen_id(&v, &into)?;
94						// Pass the value to the iterator
95						i.ingest(iterable(id, v, self.relation)?)
96					}
97					v => {
98						return Err(Error::InsertStatement {
99							value: v.to_string(),
100						})
101					}
102				}
103			}
104			_ => unreachable!(),
105		}
106		// Assign the statement
107		let stm = Statement::from(self);
108		// Output the results
109		i.output(stk, ctx, opt, &stm).await
110	}
111}
112
113impl fmt::Display for InsertStatement {
114	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115		f.write_str("INSERT")?;
116		if self.relation {
117			f.write_str(" RELATION")?
118		}
119		if self.ignore {
120			f.write_str(" IGNORE")?
121		}
122		if let Some(into) = &self.into {
123			write!(f, " INTO {}", into)?;
124		}
125		write!(f, "{}", self.data)?;
126		if let Some(ref v) = self.update {
127			write!(f, " {v}")?
128		}
129		if let Some(ref v) = self.output {
130			write!(f, " {v}")?
131		}
132		if let Some(ref v) = self.timeout {
133			write!(f, " {v}")?
134		}
135		if self.parallel {
136			f.write_str(" PARALLEL")?
137		}
138		Ok(())
139	}
140}
141
142fn iterable(id: Thing, v: Value, relation: bool) -> Result<Iterable, Error> {
143	match relation {
144		false => Ok(Iterable::Mergeable(id, v)),
145		true => {
146			let _in = match v.pick(&*IN) {
147				Value::Thing(v) => v,
148				v => {
149					return Err(Error::InsertStatementIn {
150						value: v.to_string(),
151					})
152				}
153			};
154			let out = match v.pick(&*OUT) {
155				Value::Thing(v) => v,
156				v => {
157					return Err(Error::InsertStatementOut {
158						value: v.to_string(),
159					})
160				}
161			};
162			Ok(Iterable::Relatable(_in, id, out, Some(v)))
163		}
164	}
165}
166
167fn gen_id(v: &Value, into: &Option<Table>) -> Result<Thing, Error> {
168	match into {
169		Some(into) => v.rid().generate(into, true),
170		None => match v.rid() {
171			Value::Thing(v) => match v {
172				Thing {
173					id: Id::Generate(_),
174					..
175				} => Err(Error::InsertStatementId {
176					value: v.to_string(),
177				}),
178				v => Ok(v),
179			},
180			v => Err(Error::InsertStatementId {
181				value: v.to_string(),
182			}),
183		},
184	}
185}