surrealdb_core/sql/statements/
insert.rsuse crate::ctx::Context;
use crate::dbs::{Iterable, Iterator, Options, Statement};
use crate::doc::CursorDoc;
use crate::err::Error;
use crate::sql::paths::IN;
use crate::sql::paths::OUT;
use crate::sql::{Data, Id, Output, Table, Thing, Timeout, Value};
use derive::Store;
use reblessive::tree::Stk;
use revision::revisioned;
use serde::{Deserialize, Serialize};
use std::fmt;
#[revisioned(revision = 2)]
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Store, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[non_exhaustive]
pub struct InsertStatement {
pub into: Option<Value>,
pub data: Data,
pub ignore: bool,
pub update: Option<Data>,
pub output: Option<Output>,
pub timeout: Option<Timeout>,
pub parallel: bool,
#[revision(start = 2)]
pub relation: bool,
}
impl InsertStatement {
pub(crate) fn writeable(&self) -> bool {
true
}
pub(crate) async fn compute(
&self,
stk: &mut Stk,
ctx: &Context<'_>,
opt: &Options,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
opt.valid_for_db()?;
let mut i = Iterator::new();
let opt = &opt.new_with_futures(false).with_projections(false);
let into = match &self.into {
None => None,
Some(into) => match into.compute(stk, ctx, opt, doc).await? {
Value::Table(into) => Some(into),
v => {
return Err(Error::InsertStatement {
value: v.to_string(),
})
}
},
};
match &self.data {
Data::ValuesExpression(v) => {
for v in v {
let mut o = Value::base();
for (k, v) in v.iter() {
let v = v.compute(stk, ctx, opt, None).await?;
o.set(stk, ctx, opt, k, v).await?;
}
let id = gen_id(&o, &into)?;
i.ingest(iterable(id, o, self.relation)?)
}
}
Data::SingleExpression(v) => {
let v = v.compute(stk, ctx, opt, doc).await?;
match v {
Value::Array(v) => {
for v in v {
let id = gen_id(&v, &into)?;
i.ingest(iterable(id, v, self.relation)?)
}
}
Value::Object(_) => {
let id = gen_id(&v, &into)?;
i.ingest(iterable(id, v, self.relation)?)
}
v => {
return Err(Error::InsertStatement {
value: v.to_string(),
})
}
}
}
_ => unreachable!(),
}
let stm = Statement::from(self);
i.output(stk, ctx, opt, &stm).await
}
}
impl fmt::Display for InsertStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("INSERT")?;
if self.relation {
f.write_str(" RELATION")?
}
if self.ignore {
f.write_str(" IGNORE")?
}
if let Some(into) = &self.into {
write!(f, " INTO {}", into)?;
}
write!(f, "{}", self.data)?;
if let Some(ref v) = self.update {
write!(f, " {v}")?
}
if let Some(ref v) = self.output {
write!(f, " {v}")?
}
if let Some(ref v) = self.timeout {
write!(f, " {v}")?
}
if self.parallel {
f.write_str(" PARALLEL")?
}
Ok(())
}
}
fn iterable(id: Thing, v: Value, relation: bool) -> Result<Iterable, Error> {
match relation {
false => Ok(Iterable::Mergeable(id, v)),
true => {
let _in = match v.pick(&*IN) {
Value::Thing(v) => v,
v => {
return Err(Error::InsertStatementIn {
value: v.to_string(),
})
}
};
let out = match v.pick(&*OUT) {
Value::Thing(v) => v,
v => {
return Err(Error::InsertStatementOut {
value: v.to_string(),
})
}
};
Ok(Iterable::Relatable(_in, id, out, Some(v)))
}
}
}
fn gen_id(v: &Value, into: &Option<Table>) -> Result<Thing, Error> {
match into {
Some(into) => v.rid().generate(into, true),
None => match v.rid() {
Value::Thing(v) => match v {
Thing {
id: Id::Generate(_),
..
} => Err(Error::InsertStatementId {
value: v.to_string(),
}),
v => Ok(v),
},
v => Err(Error::InsertStatementId {
value: v.to_string(),
}),
},
}
}