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.
118 lines
2.7 KiB
Rust
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))
|
|
}
|
|
}
|