surrealdb_core/sql/statements/
insert.rs1use 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 pub(crate) fn writeable(&self) -> bool {
33 true
34 }
35 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 opt.valid_for_db()?;
45 let mut i = Iterator::new();
47 let opt = &opt.new_with_futures(false).with_projections(false);
49 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 match &self.data {
63 Data::ValuesExpression(v) => {
65 for v in v {
66 let mut o = Value::base();
68 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 let id = gen_id(&o, &into)?;
75 i.ingest(iterable(id, o, self.relation)?)
77 }
78 }
79 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 let id = gen_id(&v, &into)?;
87 i.ingest(iterable(id, v, self.relation)?)
89 }
90 }
91 Value::Object(_) => {
92 let id = gen_id(&v, &into)?;
94 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 let stm = Statement::from(self);
108 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}