surrealpatch/lib/src/sql/statements/update.rs
Tobie Morgan Hitchcock 7710451d7b Remove serde serialization field skipping
Due to a bug in msgpack-rust (https://github.com/3Hren/msgpack-rust/issues/86), in order to have correct serialization<->deserialization of data, we need to ensure all fields are serialized even when empty. This will affect the output size of the data, but will ensure that once serialized, the data is deserialized without issue.
2022-02-23 11:18:46 +00:00

118 lines
2.7 KiB
Rust

use crate::dbs::Iterator;
use crate::dbs::Level;
use crate::dbs::Options;
use crate::dbs::Runtime;
use crate::dbs::Statement;
use crate::dbs::Transaction;
use crate::err::Error;
use crate::sql::comment::shouldbespace;
use crate::sql::cond::{cond, Cond};
use crate::sql::data::{data, Data};
use crate::sql::error::IResult;
use crate::sql::output::{output, Output};
use crate::sql::timeout::{timeout, Timeout};
use crate::sql::value::{whats, Value, Values};
use nom::bytes::complete::tag_no_case;
use nom::combinator::opt;
use nom::sequence::preceded;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
pub struct UpdateStatement {
pub what: Values,
pub data: Option<Data>,
pub cond: Option<Cond>,
pub output: Option<Output>,
pub timeout: Option<Timeout>,
}
impl UpdateStatement {
pub async fn compute(
&self,
ctx: &Runtime,
opt: &Options,
txn: &Transaction,
doc: Option<&Value>,
) -> Result<Value, Error> {
// Allowed to run?
opt.check(Level::No)?;
// Create a new iterator
let mut i = Iterator::new();
// Pass in current statement
i.stmt = Statement::from(self);
// Ensure futures are stored
let opt = &opt.futures(false);
// Loop over the update targets
for w in self.what.0.iter() {
let v = w.compute(ctx, opt, txn, doc).await?;
match v {
Value::Table(_) => i.prepare(v),
Value::Thing(_) => i.prepare(v),
Value::Model(_) => i.prepare(v),
Value::Array(_) => i.prepare(v),
v => {
return Err(Error::UpdateStatementError {
value: v,
})
}
};
}
// Output the results
i.output(ctx, opt, txn).await
}
}
impl fmt::Display for UpdateStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "UPDATE {}", self.what)?;
if let Some(ref v) = self.data {
write!(f, " {}", v)?
}
if let Some(ref v) = self.cond {
write!(f, " {}", v)?
}
if let Some(ref v) = self.output {
write!(f, " {}", v)?
}
if let Some(ref v) = self.timeout {
write!(f, " {}", v)?
}
Ok(())
}
}
pub fn update(i: &str) -> IResult<&str, UpdateStatement> {
let (i, _) = tag_no_case("UPDATE")(i)?;
let (i, _) = shouldbespace(i)?;
let (i, what) = whats(i)?;
let (i, data) = opt(preceded(shouldbespace, data))(i)?;
let (i, cond) = opt(preceded(shouldbespace, cond))(i)?;
let (i, output) = opt(preceded(shouldbespace, output))(i)?;
let (i, timeout) = opt(preceded(shouldbespace, timeout))(i)?;
Ok((
i,
UpdateStatement {
what,
data,
cond,
output,
timeout,
},
))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn update_statement() {
let sql = "UPDATE test";
let res = update(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("UPDATE test", format!("{}", out))
}
}