Allow PATCH clauses to accept parameters
This commit is contained in:
parent
63d099e305
commit
4ab552a8e3
9 changed files with 55 additions and 47 deletions
|
@ -64,15 +64,19 @@ impl<'a> Document<'a> {
|
|||
}
|
||||
}
|
||||
Data::PatchExpression(data) => {
|
||||
let data = data.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
self.current.to_mut().patch(ctx, opt, txn, data).await?
|
||||
}
|
||||
Data::MergeExpression(data) => {
|
||||
let data = data.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
self.current.to_mut().merge(ctx, opt, txn, data).await?
|
||||
}
|
||||
Data::ReplaceExpression(data) => {
|
||||
let data = data.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
self.current.to_mut().replace(ctx, opt, txn, data).await?
|
||||
}
|
||||
Data::ContentExpression(data) => {
|
||||
let data = data.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
self.current.to_mut().replace(ctx, opt, txn, data).await?
|
||||
}
|
||||
_ => unreachable!(),
|
||||
|
|
|
@ -20,6 +20,7 @@ impl<'a> Document<'a> {
|
|||
self.current.to_mut().def(ctx, opt, txn, rid).await?;
|
||||
// This is an INSERT statement
|
||||
if let Workable::Insert(v) = &self.extras {
|
||||
let v = v.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
self.current.to_mut().merge(ctx, opt, txn, v).await?;
|
||||
}
|
||||
// Set default field values
|
||||
|
|
|
@ -105,17 +105,6 @@ impl Array {
|
|||
_ => [self.0.remove(0).as_float(), self.0.remove(0).as_float()],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_operations(&self) -> Result<Vec<Operation>, Error> {
|
||||
self.iter()
|
||||
.map(|v| match v {
|
||||
Value::Object(v) => v.to_operation(),
|
||||
_ => Err(Error::InvalidPatch {
|
||||
message: String::from("Operation must be an object"),
|
||||
}),
|
||||
})
|
||||
.collect::<Result<Vec<_>, Error>>()
|
||||
}
|
||||
}
|
||||
|
||||
impl Array {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::sql::array::{array, Array};
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::common::commas;
|
||||
|
@ -16,7 +15,7 @@ use std::fmt;
|
|||
pub enum Data {
|
||||
EmptyExpression,
|
||||
SetExpression(Vec<(Idiom, Operator, Value)>),
|
||||
PatchExpression(Array),
|
||||
PatchExpression(Value),
|
||||
MergeExpression(Value),
|
||||
ReplaceExpression(Value),
|
||||
ContentExpression(Value),
|
||||
|
@ -98,7 +97,7 @@ fn set(i: &str) -> IResult<&str, Data> {
|
|||
fn patch(i: &str) -> IResult<&str, Data> {
|
||||
let (i, _) = tag_no_case("PATCH")(i)?;
|
||||
let (i, _) = shouldbespace(i)?;
|
||||
let (i, v) = array(i)?;
|
||||
let (i, v) = value(i)?;
|
||||
Ok((i, Data::PatchExpression(v)))
|
||||
}
|
||||
|
||||
|
|
|
@ -86,14 +86,13 @@ impl Value {
|
|||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::sql::array::Array;
|
||||
use crate::sql::test::Parse;
|
||||
|
||||
#[test]
|
||||
fn diff_none() {
|
||||
let old = Value::parse("{ test: true, text: 'text', other: { something: true } }");
|
||||
let now = Value::parse("{ test: true, text: 'text', other: { something: true } }");
|
||||
let res = Array::parse("[]");
|
||||
let res = Value::parse("[]");
|
||||
assert_eq!(res.to_operations().unwrap(), old.diff(&now, Idiom::default()));
|
||||
}
|
||||
|
||||
|
@ -101,7 +100,7 @@ mod tests {
|
|||
fn diff_add() {
|
||||
let old = Value::parse("{ test: true }");
|
||||
let now = Value::parse("{ test: true, other: 'test' }");
|
||||
let res = Array::parse("[{ op: 'add', path: '/other', value: 'test' }]");
|
||||
let res = Value::parse("[{ op: 'add', path: '/other', value: 'test' }]");
|
||||
assert_eq!(res.to_operations().unwrap(), old.diff(&now, Idiom::default()));
|
||||
}
|
||||
|
||||
|
@ -109,7 +108,7 @@ mod tests {
|
|||
fn diff_remove() {
|
||||
let old = Value::parse("{ test: true, other: 'test' }");
|
||||
let now = Value::parse("{ test: true }");
|
||||
let res = Array::parse("[{ op: 'remove', path: '/other' }]");
|
||||
let res = Value::parse("[{ op: 'remove', path: '/other' }]");
|
||||
assert_eq!(res.to_operations().unwrap(), old.diff(&now, Idiom::default()));
|
||||
}
|
||||
|
||||
|
@ -117,7 +116,7 @@ mod tests {
|
|||
fn diff_add_array() {
|
||||
let old = Value::parse("{ test: [1,2,3] }");
|
||||
let now = Value::parse("{ test: [1,2,3,4] }");
|
||||
let res = Array::parse("[{ op: 'add', path: '/test/3', value: 4 }]");
|
||||
let res = Value::parse("[{ op: 'add', path: '/test/3', value: 4 }]");
|
||||
assert_eq!(res.to_operations().unwrap(), old.diff(&now, Idiom::default()));
|
||||
}
|
||||
|
||||
|
@ -125,7 +124,7 @@ mod tests {
|
|||
fn diff_replace_embedded() {
|
||||
let old = Value::parse("{ test: { other: 'test' } }");
|
||||
let now = Value::parse("{ test: { other: false } }");
|
||||
let res = Array::parse("[{ op: 'replace', path: '/test/other', value: false }]");
|
||||
let res = Value::parse("[{ op: 'replace', path: '/test/other', value: false }]");
|
||||
assert_eq!(res.to_operations().unwrap(), old.diff(&now, Idiom::default()));
|
||||
}
|
||||
|
||||
|
@ -133,7 +132,7 @@ mod tests {
|
|||
fn diff_change_text() {
|
||||
let old = Value::parse("{ test: { other: 'test' } }");
|
||||
let now = Value::parse("{ test: { other: 'text' } }");
|
||||
let res = Array::parse(
|
||||
let res = Value::parse(
|
||||
"[{ op: 'change', path: '/test/other', value: '@@ -1,4 +1,4 @@\n te\n-s\n+x\n t\n' }]",
|
||||
);
|
||||
assert_eq!(res.to_operations().unwrap(), old.diff(&now, Idiom::default()));
|
||||
|
|
|
@ -11,9 +11,9 @@ impl Value {
|
|||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
val: &Value,
|
||||
val: Value,
|
||||
) -> Result<(), Error> {
|
||||
match val.compute(ctx, opt, txn, Some(self)).await? {
|
||||
match val {
|
||||
Value::Object(v) => {
|
||||
for (k, v) in v {
|
||||
self.set(ctx, opt, txn, &[Part::from(k)], v).await?;
|
||||
|
|
|
@ -2,7 +2,6 @@ use crate::ctx::Context;
|
|||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::sql::array::Array;
|
||||
use crate::sql::operation::Op;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
|
@ -12,7 +11,7 @@ impl Value {
|
|||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
val: &Array,
|
||||
val: Value,
|
||||
) -> Result<(), Error> {
|
||||
for o in val.to_operations()?.into_iter() {
|
||||
match o.op {
|
||||
|
@ -51,9 +50,9 @@ mod tests {
|
|||
async fn patch_add_simple() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let ops = Array::parse("[{ op: 'add', path: '/temp', value: true }]");
|
||||
let ops = Value::parse("[{ op: 'add', path: '/temp', value: true }]");
|
||||
let res = Value::parse("{ test: { other: null, something: 123 }, temp: true }");
|
||||
val.patch(&ctx, &opt, &txn, &ops).await.unwrap();
|
||||
val.patch(&ctx, &opt, &txn, ops).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
|
@ -61,9 +60,9 @@ mod tests {
|
|||
async fn patch_remove_simple() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 }, temp: true }");
|
||||
let ops = Array::parse("[{ op: 'remove', path: '/temp' }]");
|
||||
let ops = Value::parse("[{ op: 'remove', path: '/temp' }]");
|
||||
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
val.patch(&ctx, &opt, &txn, &ops).await.unwrap();
|
||||
val.patch(&ctx, &opt, &txn, ops).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
|
@ -71,9 +70,9 @@ mod tests {
|
|||
async fn patch_replace_simple() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 }, temp: true }");
|
||||
let ops = Array::parse("[{ op: 'replace', path: '/temp', value: 'text' }]");
|
||||
let ops = Value::parse("[{ op: 'replace', path: '/temp', value: 'text' }]");
|
||||
let res = Value::parse("{ test: { other: null, something: 123 }, temp: 'text' }");
|
||||
val.patch(&ctx, &opt, &txn, &ops).await.unwrap();
|
||||
val.patch(&ctx, &opt, &txn, ops).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
|
@ -81,11 +80,11 @@ mod tests {
|
|||
async fn patch_change_simple() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 }, temp: 'test' }");
|
||||
let ops = Array::parse(
|
||||
let ops = Value::parse(
|
||||
"[{ op: 'change', path: '/temp', value: '@@ -1,4 +1,4 @@\n te\n-s\n+x\n t\n' }]",
|
||||
);
|
||||
let res = Value::parse("{ test: { other: null, something: 123 }, temp: 'text' }");
|
||||
val.patch(&ctx, &opt, &txn, &ops).await.unwrap();
|
||||
val.patch(&ctx, &opt, &txn, ops).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
|
@ -93,9 +92,9 @@ mod tests {
|
|||
async fn patch_add_embedded() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let ops = Array::parse("[{ op: 'add', path: '/temp/test', value: true }]");
|
||||
let ops = Value::parse("[{ op: 'add', path: '/temp/test', value: true }]");
|
||||
let res = Value::parse("{ test: { other: null, something: 123 }, temp: { test: true } }");
|
||||
val.patch(&ctx, &opt, &txn, &ops).await.unwrap();
|
||||
val.patch(&ctx, &opt, &txn, ops).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
|
@ -103,9 +102,9 @@ mod tests {
|
|||
async fn patch_remove_embedded() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 }, temp: true }");
|
||||
let ops = Array::parse("[{ op: 'remove', path: '/test/other' }]");
|
||||
let ops = Value::parse("[{ op: 'remove', path: '/test/other' }]");
|
||||
let res = Value::parse("{ test: { something: 123 }, temp: true }");
|
||||
val.patch(&ctx, &opt, &txn, &ops).await.unwrap();
|
||||
val.patch(&ctx, &opt, &txn, ops).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
|
@ -113,9 +112,9 @@ mod tests {
|
|||
async fn patch_replace_embedded() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 }, temp: true }");
|
||||
let ops = Array::parse("[{ op: 'replace', path: '/test/other', value: 'text' }]");
|
||||
let ops = Value::parse("[{ op: 'replace', path: '/test/other', value: 'text' }]");
|
||||
let res = Value::parse("{ test: { other: 'text', something: 123 }, temp: true }");
|
||||
val.patch(&ctx, &opt, &txn, &ops).await.unwrap();
|
||||
val.patch(&ctx, &opt, &txn, ops).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
|
@ -123,11 +122,11 @@ mod tests {
|
|||
async fn patch_change_embedded() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let mut val = Value::parse("{ test: { other: 'test', something: 123 }, temp: true }");
|
||||
let ops = Array::parse(
|
||||
let ops = Value::parse(
|
||||
"[{ op: 'change', path: '/test/other', value: '@@ -1,4 +1,4 @@\n te\n-s\n+x\n t\n' }]",
|
||||
);
|
||||
let res = Value::parse("{ test: { other: 'text', something: 123 }, temp: true }");
|
||||
val.patch(&ctx, &opt, &txn, &ops).await.unwrap();
|
||||
val.patch(&ctx, &opt, &txn, ops).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,13 +7,13 @@ use crate::sql::value::Value;
|
|||
impl Value {
|
||||
pub async fn replace(
|
||||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
val: &Value,
|
||||
_ctx: &Context<'_>,
|
||||
_opt: &Options,
|
||||
_txn: &Transaction,
|
||||
val: Value,
|
||||
) -> Result<(), Error> {
|
||||
// Clear all entries
|
||||
match val.compute(ctx, opt, txn, Some(self)).await? {
|
||||
match val {
|
||||
Value::Object(v) => {
|
||||
*self = Value::from(v);
|
||||
Ok(())
|
||||
|
@ -36,7 +36,7 @@ mod tests {
|
|||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let res = Value::parse("{ other: true }");
|
||||
let obj = Value::parse("{ other: true }");
|
||||
val.replace(&ctx, &opt, &txn, &obj).await.unwrap();
|
||||
val.replace(&ctx, &opt, &txn, obj).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -708,6 +708,23 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_operations(&self) -> Result<Vec<Operation>, Error> {
|
||||
match self {
|
||||
Value::Array(v) => v
|
||||
.iter()
|
||||
.map(|v| match v {
|
||||
Value::Object(v) => v.to_operation(),
|
||||
_ => Err(Error::InvalidPatch {
|
||||
message: String::from("Operation must be an object"),
|
||||
}),
|
||||
})
|
||||
.collect::<Result<Vec<_>, Error>>(),
|
||||
_ => Err(Error::InvalidPatch {
|
||||
message: String::from("Operations must be an array"),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
// Simple conversion of value
|
||||
// -----------------------------------
|
||||
|
|
Loading…
Reference in a new issue