surrealdb_core/sql/statements/
insert.rs1use crate::ctx::{Context, MutableContext};
2use crate::dbs::{Iterable, Iterator, Options, Statement};
3use crate::doc::CursorDoc;
4use crate::err::Error;
5use crate::idx::planner::RecordStrategy;
6use crate::sql::paths::IN;
7use crate::sql::paths::OUT;
8use crate::sql::{Data, Id, Output, Table, Thing, Timeout, Value, Version};
9
10use reblessive::tree::Stk;
11use revision::revisioned;
12use serde::{Deserialize, Serialize};
13use std::fmt;
14
15#[revisioned(revision = 3)]
16#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
17#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
18#[non_exhaustive]
19pub struct InsertStatement {
20 pub into: Option<Value>,
21 pub data: Data,
22 pub ignore: bool,
23 pub update: Option<Data>,
24 pub output: Option<Output>,
25 pub timeout: Option<Timeout>,
26 pub parallel: bool,
27 #[revision(start = 2)]
28 pub relation: bool,
29 #[revision(start = 3)]
30 pub version: Option<Version>,
31}
32
33impl InsertStatement {
34 pub(crate) fn writeable(&self) -> bool {
36 true
37 }
38 pub(crate) async fn compute(
40 &self,
41 stk: &mut Stk,
42 ctx: &Context,
43 opt: &Options,
44 doc: Option<&CursorDoc>,
45 ) -> Result<Value, Error> {
46 opt.valid_for_db()?;
48 let mut i = Iterator::new();
50 let version = match &self.version {
52 Some(v) => Some(v.compute(stk, ctx, opt, doc).await?),
53 _ => None,
54 };
55 let opt = &opt.new_with_futures(false).with_version(version);
57 let ctx = match self.timeout.as_ref() {
59 Some(timeout) => {
60 let mut ctx = MutableContext::new(ctx);
61 ctx.add_timeout(*timeout.0)?;
62 ctx.freeze()
63 }
64 None => ctx.clone(),
65 };
66 let into = match &self.into {
68 None => None,
69 Some(into) => match into.compute(stk, &ctx, opt, doc).await? {
70 Value::Table(into) => Some(into),
71 v => {
72 return Err(Error::InsertStatement {
73 value: v.to_string(),
74 })
75 }
76 },
77 };
78 match &self.data {
80 Data::ValuesExpression(v) => {
82 for v in v {
83 let mut o = Value::base();
85 for (k, v) in v.iter() {
87 let v = v.compute(stk, &ctx, opt, None).await?;
88 o.set(stk, &ctx, opt, k, v).await?;
89 }
90 let id = gen_id(&o, &into)?;
92 i.ingest(iterable(id, o, self.relation)?)
94 }
95 }
96 Data::SingleExpression(v) => {
98 let v = v.compute(stk, &ctx, opt, doc).await?;
99 match v {
100 Value::Array(v) => {
101 for v in v {
102 let id = gen_id(&v, &into)?;
104 i.ingest(iterable(id, v, self.relation)?)
106 }
107 }
108 Value::Object(_) => {
109 let id = gen_id(&v, &into)?;
111 i.ingest(iterable(id, v, self.relation)?)
113 }
114 v => {
115 return Err(Error::InsertStatement {
116 value: v.to_string(),
117 })
118 }
119 }
120 }
121 v => return Err(fail!("Unknown data clause type in INSERT statement: {v:?}")),
122 }
123 let stm = Statement::from(self);
125 let res = i.output(stk, &ctx, opt, &stm, RecordStrategy::KeysAndValues).await?;
127 if ctx.is_timedout() {
129 return Err(Error::QueryTimedout);
130 }
131 Ok(res)
133 }
134}
135
136impl fmt::Display for InsertStatement {
137 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
138 f.write_str("INSERT")?;
139 if self.relation {
140 f.write_str(" RELATION")?
141 }
142 if self.ignore {
143 f.write_str(" IGNORE")?
144 }
145 if let Some(into) = &self.into {
146 write!(f, " INTO {}", into)?;
147 }
148 write!(f, " {}", self.data)?;
149 if let Some(ref v) = self.update {
150 write!(f, " {v}")?
151 }
152 if let Some(ref v) = self.output {
153 write!(f, " {v}")?
154 }
155 if let Some(ref v) = self.version {
156 write!(f, " {v}")?
157 }
158 if let Some(ref v) = self.timeout {
159 write!(f, " {v}")?
160 }
161 if self.parallel {
162 f.write_str(" PARALLEL")?
163 }
164 Ok(())
165 }
166}
167
168fn iterable(id: Thing, v: Value, relation: bool) -> Result<Iterable, Error> {
169 match relation {
170 false => Ok(Iterable::Mergeable(id, v)),
171 true => {
172 let f = match v.pick(&*IN) {
173 Value::Thing(v) => v,
174 v => {
175 return Err(Error::InsertStatementIn {
176 value: v.to_string(),
177 })
178 }
179 };
180 let w = match v.pick(&*OUT) {
181 Value::Thing(v) => v,
182 v => {
183 return Err(Error::InsertStatementOut {
184 value: v.to_string(),
185 })
186 }
187 };
188 Ok(Iterable::Relatable(f, id, w, Some(v)))
189 }
190 }
191}
192
193fn gen_id(v: &Value, into: &Option<Table>) -> Result<Thing, Error> {
194 match into {
195 Some(into) => v.rid().generate(into, true),
196 None => match v.rid() {
197 Value::Thing(v) => match v {
198 Thing {
199 id: Id::Generate(_),
200 ..
201 } => Err(Error::InsertStatementId {
202 value: v.to_string(),
203 }),
204 v => Ok(v),
205 },
206 v => Err(Error::InsertStatementId {
207 value: v.to_string(),
208 }),
209 },
210 }
211}