surrealdb_core/sql/statements/
create.rs

1use crate::ctx::Context;
2use crate::dbs::{Iterator, Options, Statement};
3use crate::doc::CursorDoc;
4use crate::err::Error;
5use crate::idx::planner::{QueryPlanner, RecordStrategy, StatementContext};
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 = stm.setup_timeout(ctx)?;
64		// Get a query planner
65		let mut planner = QueryPlanner::new();
66		let stm_ctx = StatementContext::new(&ctx, opt, &stm)?;
67		// Loop over the create targets
68		for w in self.what.0.iter() {
69			let v = w.compute(stk, &ctx, opt, doc).await?;
70			i.prepare(stk, &mut planner, &stm_ctx, v).await.map_err(|e| match e {
71				Error::InvalidStatementTarget {
72					value: v,
73				} => Error::CreateStatement {
74					value: v,
75				},
76				e => e,
77			})?;
78		}
79		// Attach the query planner to the context
80		let ctx = stm.setup_query_planner(planner, ctx);
81		// Process the statement
82		let res = i.output(stk, &ctx, opt, &stm, RecordStrategy::KeysAndValues).await?;
83		// Catch statement timeout
84		if ctx.is_timedout()? {
85			return Err(Error::QueryTimedout);
86		}
87		// Output the results
88		match res {
89			// This is a single record result
90			Value::Array(mut a) if self.only => match a.len() {
91				// There was exactly one result
92				1 => Ok(a.remove(0)),
93				// There were no results
94				_ => Err(Error::SingleOnlyOutput),
95			},
96			// This is standard query result
97			v => Ok(v),
98		}
99	}
100}
101
102impl fmt::Display for CreateStatement {
103	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
104		write!(f, "CREATE")?;
105		if self.only {
106			f.write_str(" ONLY")?
107		}
108		write!(f, " {}", self.what)?;
109		if let Some(ref v) = self.data {
110			write!(f, " {v}")?
111		}
112		if let Some(ref v) = self.output {
113			write!(f, " {v}")?
114		}
115		if let Some(ref v) = self.version {
116			write!(f, " {v}")?
117		}
118		if let Some(ref v) = self.timeout {
119			write!(f, " {v}")?
120		}
121		if self.parallel {
122			f.write_str(" PARALLEL")?
123		}
124		Ok(())
125	}
126}