surrealdb_core/sql/statements/
create.rs

1use crate::ctx::{Context, MutableContext};
2use crate::dbs::{Iterator, Options, Statement};
3use crate::doc::CursorDoc;
4use crate::err::Error;
5use crate::idx::planner::RecordStrategy;
6use crate::sql::{Data, Output, Timeout, Value, Values, Version};
7
8use reblessive::tree::Stk;
9use revision::revisioned;
10use serde::{Deserialize, Serialize};
11use std::fmt;
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 CreateStatement {
18	// A keyword modifier indicating if we are expecting a single result or several
19	#[revision(start = 2)]
20	pub only: bool,
21	// Where we are creating (i.e. table, or record ID)
22	pub what: Values,
23	// The data associated with the record being created
24	pub data: Option<Data>,
25	//  What the result of the statement should resemble (i.e. Diff or no result etc).
26	pub output: Option<Output>,
27	// The timeout for the statement
28	pub timeout: Option<Timeout>,
29	// If the statement should be run in parallel
30	pub parallel: bool,
31	// Version as nanosecond timestamp passed down to Datastore
32	#[revision(start = 3)]
33	pub version: Option<Version>,
34}
35
36impl CreateStatement {
37	/// Check if we require a writeable transaction
38	pub(crate) fn writeable(&self) -> bool {
39		true
40	}
41	/// Process this type returning a computed simple Value
42	pub(crate) async fn compute(
43		&self,
44		stk: &mut Stk,
45		ctx: &Context,
46		opt: &Options,
47		doc: Option<&CursorDoc>,
48	) -> Result<Value, Error> {
49		// Valid options?
50		opt.valid_for_db()?;
51		// Create a new iterator
52		let mut i = Iterator::new();
53		// Assign the statement
54		let stm = Statement::from(self);
55		// Propagate the version to the underlying datastore
56		let version = match &self.version {
57			Some(v) => Some(v.compute(stk, ctx, opt, doc).await?),
58			_ => None,
59		};
60		// Ensure futures are stored
61		let opt = &opt.new_with_futures(false).with_version(version);
62		// Check if there is a timeout
63		let ctx = match self.timeout.as_ref() {
64			Some(timeout) => {
65				let mut ctx = MutableContext::new(ctx);
66				ctx.add_timeout(*timeout.0)?;
67				ctx.freeze()
68			}
69			None => ctx.clone(),
70		};
71		// Loop over the create targets
72		for w in self.what.0.iter() {
73			let v = w.compute(stk, &ctx, opt, doc).await?;
74			i.prepare(&stm, v).map_err(|e| match e {
75				Error::InvalidStatementTarget {
76					value: v,
77				} => Error::CreateStatement {
78					value: v,
79				},
80				e => e,
81			})?;
82		}
83		// Process the statement
84		let res = i.output(stk, &ctx, opt, &stm, RecordStrategy::KeysAndValues).await?;
85		// Catch statement timeout
86		if ctx.is_timedout() {
87			return Err(Error::QueryTimedout);
88		}
89		// Output the results
90		match res {
91			// This is a single record result
92			Value::Array(mut a) if self.only => match a.len() {
93				// There was exactly one result
94				1 => Ok(a.remove(0)),
95				// There were no results
96				_ => Err(Error::SingleOnlyOutput),
97			},
98			// This is standard query result
99			v => Ok(v),
100		}
101	}
102}
103
104impl fmt::Display for CreateStatement {
105	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106		write!(f, "CREATE")?;
107		if self.only {
108			f.write_str(" ONLY")?
109		}
110		write!(f, " {}", self.what)?;
111		if let Some(ref v) = self.data {
112			write!(f, " {v}")?
113		}
114		if let Some(ref v) = self.output {
115			write!(f, " {v}")?
116		}
117		if let Some(ref v) = self.version {
118			write!(f, " {v}")?
119		}
120		if let Some(ref v) = self.timeout {
121			write!(f, " {v}")?
122		}
123		if self.parallel {
124			f.write_str(" PARALLEL")?
125		}
126		Ok(())
127	}
128}