parent
4dba9fc675
commit
1102a2c6da
7 changed files with 192 additions and 11 deletions
|
@ -56,6 +56,9 @@ impl<'a> Document<'a> {
|
|||
Operator::Dec => {
|
||||
self.current.to_mut().decrement(ctx, opt, txn, &x.0, v).await?
|
||||
}
|
||||
Operator::Ext => {
|
||||
self.current.to_mut().extend(ctx, opt, txn, &x.0, v).await?
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ pub enum Operator {
|
|||
Pow, // **
|
||||
Inc, // +=
|
||||
Dec, // -=
|
||||
Ext, // +?=
|
||||
//
|
||||
Equal, // =
|
||||
Exact, // ==
|
||||
|
@ -93,6 +94,7 @@ impl fmt::Display for Operator {
|
|||
Self::Pow => "**",
|
||||
Self::Inc => "+=",
|
||||
Self::Dec => "-=",
|
||||
Self::Ext => "+=?",
|
||||
Self::Equal => "=",
|
||||
Self::Exact => "==",
|
||||
Self::NotEqual => "!=",
|
||||
|
@ -127,6 +129,7 @@ pub fn assigner(i: &str) -> IResult<&str, Operator> {
|
|||
map(char('='), |_| Operator::Equal),
|
||||
map(tag("+="), |_| Operator::Inc),
|
||||
map(tag("-="), |_| Operator::Dec),
|
||||
map(tag("+?="), |_| Operator::Ext),
|
||||
))(i)
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ mod tests {
|
|||
use crate::sql::test::Parse;
|
||||
|
||||
#[tokio::test]
|
||||
async fn dec_none() {
|
||||
async fn decrement_none() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("other");
|
||||
let mut val = Value::parse("{ test: 100 }");
|
||||
|
@ -54,7 +54,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn dec_number() {
|
||||
async fn decrement_number() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: 100 }");
|
||||
|
@ -64,7 +64,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn dec_array_number() {
|
||||
async fn decrement_array_number() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test[1]");
|
||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||
|
@ -74,7 +74,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn dec_array_value() {
|
||||
async fn decrement_array_value() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||
|
@ -84,7 +84,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn dec_array_array() {
|
||||
async fn decrement_array_array() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||
|
|
59
lib/src/sql/value/extend.rs
Normal file
59
lib/src/sql/value/extend.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::sql::array::Uniq;
|
||||
use crate::sql::part::Part;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
impl Value {
|
||||
pub async fn extend(
|
||||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
path: &[Part],
|
||||
val: Value,
|
||||
) -> Result<(), Error> {
|
||||
match self.get(ctx, opt, txn, path).await? {
|
||||
Value::Array(v) => match val {
|
||||
Value::Array(x) => self.set(ctx, opt, txn, path, Value::from((v + x).uniq())).await,
|
||||
x => self.set(ctx, opt, txn, path, Value::from((v + x).uniq())).await,
|
||||
},
|
||||
Value::None => match val {
|
||||
Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(x)).await,
|
||||
x => self.set(ctx, opt, txn, path, Value::from(vec![x])).await,
|
||||
},
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::dbs::test::mock;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::test::Parse;
|
||||
|
||||
#[tokio::test]
|
||||
async fn extend_array_value() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||
let res = Value::parse("{ test: [100, 200, 300] }");
|
||||
val.extend(&ctx, &opt, &txn, &idi, Value::from(200)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn extend_array_array() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||
let res = Value::parse("{ test: [100, 200, 300, 400, 500] }");
|
||||
val.extend(&ctx, &opt, &txn, &idi, Value::parse("[100, 300, 400, 500]")).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
}
|
|
@ -45,7 +45,7 @@ mod tests {
|
|||
use crate::sql::test::Parse;
|
||||
|
||||
#[tokio::test]
|
||||
async fn inc_none() {
|
||||
async fn increment_none() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("other");
|
||||
let mut val = Value::parse("{ test: 100 }");
|
||||
|
@ -55,7 +55,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn inc_number() {
|
||||
async fn increment_number() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: 100 }");
|
||||
|
@ -65,7 +65,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn inc_array_number() {
|
||||
async fn increment_array_number() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test[1]");
|
||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||
|
@ -75,7 +75,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn inc_array_value() {
|
||||
async fn increment_array_value() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||
|
@ -85,7 +85,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn inc_array_array() {
|
||||
async fn increment_array_array() {
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||
|
|
|
@ -13,6 +13,7 @@ mod del;
|
|||
mod diff;
|
||||
mod each;
|
||||
mod every;
|
||||
mod extend;
|
||||
mod fetch;
|
||||
mod first;
|
||||
mod flatten;
|
||||
|
|
|
@ -102,7 +102,122 @@ async fn subquery_select() -> Result<(), Error> {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn subquery_ifelse() -> Result<(), Error> {
|
||||
async fn subquery_ifelse_set() -> Result<(), Error> {
|
||||
let sql = "
|
||||
-- Check if the record exists
|
||||
LET $record = (SELECT *, count() AS count FROM person:test);
|
||||
-- Return the specified record
|
||||
RETURN $record;
|
||||
-- Update the record field if it exists
|
||||
IF $record.count THEN
|
||||
(UPDATE person:test SET sport +?= 'football' RETURN sport)
|
||||
ELSE
|
||||
(UPDATE person:test SET sport = ['basketball'] RETURN sport)
|
||||
END;
|
||||
-- Check if the record exists
|
||||
LET $record = SELECT *, count() AS count FROM person:test;
|
||||
-- Return the specified record
|
||||
RETURN $record;
|
||||
-- Update the record field if it exists
|
||||
IF $record.count THEN
|
||||
UPDATE person:test SET sport +?= 'football' RETURN sport
|
||||
ELSE
|
||||
UPDATE person:test SET sport = ['basketball'] RETURN sport
|
||||
END;
|
||||
-- Check if the record exists
|
||||
LET $record = SELECT *, count() AS count FROM person:test;
|
||||
-- Return the specified record
|
||||
RETURN $record;
|
||||
-- Update the record field if it exists
|
||||
IF $record.count THEN
|
||||
UPDATE person:test SET sport +?= 'football' RETURN sport;
|
||||
ELSE
|
||||
UPDATE person:test SET sport = ['basketball'] RETURN sport;
|
||||
END;
|
||||
";
|
||||
let dbs = Datastore::new("memory").await?;
|
||||
let ses = Session::for_kv().with_ns("test").with_db("test");
|
||||
let res = &mut dbs.execute(&sql, &ses, None, false).await?;
|
||||
assert_eq!(res.len(), 9);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::None;
|
||||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::None;
|
||||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"{
|
||||
sport: [
|
||||
'basketball',
|
||||
]
|
||||
}",
|
||||
);
|
||||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::None;
|
||||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"{
|
||||
count: 1,
|
||||
id: person:test,
|
||||
sport: [
|
||||
'basketball',
|
||||
]
|
||||
}",
|
||||
);
|
||||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"{
|
||||
sport: [
|
||||
'basketball',
|
||||
'football',
|
||||
]
|
||||
}",
|
||||
);
|
||||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::None;
|
||||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"{
|
||||
count: 1,
|
||||
id: person:test,
|
||||
sport: [
|
||||
'basketball',
|
||||
'football',
|
||||
]
|
||||
}",
|
||||
);
|
||||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"{
|
||||
sport: [
|
||||
'basketball',
|
||||
'football',
|
||||
]
|
||||
}",
|
||||
);
|
||||
assert_eq!(tmp, val);
|
||||
//
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn subquery_ifelse_array() -> Result<(), Error> {
|
||||
let sql = "
|
||||
-- Check if the record exists
|
||||
LET $record = (SELECT *, count() AS count FROM person:test);
|
||||
|
|
Loading…
Reference in a new issue