surrealpatch/lib/src/sql/param.rs

147 lines
3.5 KiB
Rust
Raw Normal View History

use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Transaction;
2021-03-29 15:43:37 +00:00
use crate::err::Error;
2022-01-16 20:31:50 +00:00
use crate::sql::error::IResult;
use crate::sql::idiom;
use crate::sql::idiom::Idiom;
use crate::sql::part::Next;
use crate::sql::part::Part;
use crate::sql::value::Value;
use nom::character::complete::char;
2020-06-29 15:36:01 +00:00
use serde::{Deserialize, Serialize};
use std::fmt;
use std::ops::Deref;
2020-06-29 15:36:01 +00:00
use std::str;
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
pub struct Param(pub Idiom);
2021-03-31 11:54:20 +00:00
impl From<Idiom> for Param {
fn from(p: Idiom) -> Self {
Self(p)
}
}
impl Deref for Param {
type Target = Idiom;
fn deref(&self) -> &Self::Target {
&self.0
2021-03-31 11:54:20 +00:00
}
2020-06-29 15:36:01 +00:00
}
2022-01-14 08:12:56 +00:00
impl Param {
pub(crate) async fn compute(
2021-03-29 15:43:37 +00:00
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&Value>,
) -> Result<Value, Error> {
// Find a base variable by name
match self.first() {
// The first part will be a field
Some(Part::Field(v)) => match v.as_str() {
// This is a special param
"this" | "self" => match doc {
2022-04-05 23:11:33 +00:00
// The base document exists
Some(v) => {
// Get the path parts
let pth: &[Part] = self;
// Process the parameter value
2022-04-05 23:11:33 +00:00
let res = v.compute(ctx, opt, txn, doc).await?;
// Return the desired field
res.get(ctx, opt, txn, pth.next()).await
}
// The base document does not exist
None => Ok(Value::None),
},
// This is a normal param
_ => match ctx.value(v) {
// The param has been set locally
2022-04-05 23:11:33 +00:00
Some(v) => {
// Get the path parts
let pth: &[Part] = self;
// Process the parameter value
2022-04-05 23:11:33 +00:00
let res = v.compute(ctx, opt, txn, doc).await?;
// Return the desired field
res.get(ctx, opt, txn, pth.next()).await
}
// The param has not been set locally
None => {
// Clone transaction
let run = txn.clone();
// Claim transaction
let mut run = run.lock().await;
// Get the param definition
let val = run.get_pa(opt.ns(), opt.db(), v).await;
// Check if the param has been set globally
match val {
// The param has been set globally
Ok(v) => Ok(v.value),
// The param has not been set globally
Err(_) => Ok(Value::None),
}
}
2022-04-05 23:11:33 +00:00
},
},
_ => unreachable!(),
}
2021-03-29 15:43:37 +00:00
}
}
2022-01-14 08:12:56 +00:00
impl fmt::Display for Param {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "${}", &self.0)
2022-01-14 08:12:56 +00:00
}
}
2020-06-29 15:36:01 +00:00
pub fn param(i: &str) -> IResult<&str, Param> {
let (i, _) = char('$')(i)?;
let (i, v) = idiom::param(i)?;
2020-06-29 15:36:01 +00:00
Ok((i, Param::from(v)))
}
pub fn plain(i: &str) -> IResult<&str, Param> {
let (i, _) = char('$')(i)?;
let (i, v) = idiom::plain(i)?;
Ok((i, Param::from(v)))
}
2020-06-29 15:36:01 +00:00
#[cfg(test)]
mod tests {
use super::*;
use crate::sql::test::Parse;
2020-06-29 15:36:01 +00:00
#[test]
fn param_normal() {
let sql = "$test";
let res = param(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("$test", format!("{}", out));
assert_eq!(out, Param::parse("$test"));
2020-06-29 15:36:01 +00:00
}
#[test]
fn param_longer() {
let sql = "$test_and_deliver";
let res = param(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("$test_and_deliver", format!("{}", out));
assert_eq!(out, Param::parse("$test_and_deliver"));
2020-06-29 15:36:01 +00:00
}
2021-03-31 11:54:20 +00:00
#[test]
fn param_embedded() {
let sql = "$test.temporary[0].embedded";
let res = param(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("$test.temporary[0].embedded", format!("{}", out));
assert_eq!(out, Param::parse("$test.temporary[0].embedded"));
2021-03-31 11:54:20 +00:00
}
2020-06-29 15:36:01 +00:00
}