2022-11-03 10:55:32 +00:00
|
|
|
use crate::ctx::Context;
|
|
|
|
use crate::dbs::Options;
|
|
|
|
use crate::dbs::Transaction;
|
|
|
|
use crate::err::Error;
|
2022-08-28 22:19:59 +00:00
|
|
|
use crate::sql::error::IResult;
|
|
|
|
use crate::sql::id::{id, Id};
|
|
|
|
use crate::sql::ident::ident_raw;
|
2023-03-30 10:41:44 +00:00
|
|
|
use crate::sql::serde::is_internal_serialization;
|
2022-11-03 10:55:32 +00:00
|
|
|
use crate::sql::value::Value;
|
2022-10-30 01:11:59 +00:00
|
|
|
use nom::branch::alt;
|
2022-08-28 22:19:59 +00:00
|
|
|
use nom::character::complete::char;
|
2022-10-30 01:11:59 +00:00
|
|
|
use nom::combinator::map;
|
|
|
|
use nom::combinator::opt;
|
|
|
|
use nom::sequence::preceded;
|
|
|
|
use nom::sequence::terminated;
|
2023-03-30 10:41:44 +00:00
|
|
|
use serde::ser::SerializeStruct;
|
2022-08-28 22:19:59 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2022-10-30 01:11:59 +00:00
|
|
|
use std::cmp::Ordering;
|
2022-08-28 22:19:59 +00:00
|
|
|
use std::fmt;
|
2022-10-30 01:11:59 +00:00
|
|
|
use std::ops::Bound;
|
2022-08-28 22:19:59 +00:00
|
|
|
|
2023-03-30 10:41:44 +00:00
|
|
|
pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Range";
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Hash)]
|
2022-08-28 22:19:59 +00:00
|
|
|
pub struct Range {
|
|
|
|
pub tb: String,
|
2022-10-30 01:11:59 +00:00
|
|
|
pub beg: Bound<Id>,
|
|
|
|
pub end: Bound<Id>,
|
|
|
|
}
|
|
|
|
|
2022-11-03 10:55:32 +00:00
|
|
|
impl Range {
|
|
|
|
pub(crate) async fn compute(
|
|
|
|
&self,
|
|
|
|
ctx: &Context<'_>,
|
|
|
|
opt: &Options,
|
|
|
|
txn: &Transaction,
|
|
|
|
doc: Option<&Value>,
|
|
|
|
) -> Result<Value, Error> {
|
|
|
|
Ok(Value::Range(Box::new(Range {
|
|
|
|
tb: self.tb.clone(),
|
|
|
|
beg: match &self.beg {
|
|
|
|
Bound::Included(id) => Bound::Included(id.compute(ctx, opt, txn, doc).await?),
|
|
|
|
Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt, txn, doc).await?),
|
|
|
|
Bound::Unbounded => Bound::Unbounded,
|
|
|
|
},
|
|
|
|
end: match &self.end {
|
|
|
|
Bound::Included(id) => Bound::Included(id.compute(ctx, opt, txn, doc).await?),
|
|
|
|
Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt, txn, doc).await?),
|
|
|
|
Bound::Unbounded => Bound::Unbounded,
|
|
|
|
},
|
|
|
|
})))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-30 01:11:59 +00:00
|
|
|
impl PartialOrd for Range {
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
|
|
match self.tb.partial_cmp(&other.tb) {
|
|
|
|
Some(Ordering::Equal) => match &self.beg {
|
|
|
|
Bound::Unbounded => match &other.beg {
|
|
|
|
Bound::Unbounded => Some(Ordering::Equal),
|
|
|
|
_ => Some(Ordering::Less),
|
|
|
|
},
|
|
|
|
Bound::Included(v) => match &other.beg {
|
|
|
|
Bound::Unbounded => Some(Ordering::Greater),
|
|
|
|
Bound::Included(w) => match v.partial_cmp(w) {
|
|
|
|
Some(Ordering::Equal) => match &self.end {
|
|
|
|
Bound::Unbounded => match &other.end {
|
|
|
|
Bound::Unbounded => Some(Ordering::Equal),
|
|
|
|
_ => Some(Ordering::Greater),
|
|
|
|
},
|
|
|
|
Bound::Included(v) => match &other.end {
|
|
|
|
Bound::Unbounded => Some(Ordering::Less),
|
|
|
|
Bound::Included(w) => v.partial_cmp(w),
|
|
|
|
_ => Some(Ordering::Greater),
|
|
|
|
},
|
|
|
|
Bound::Excluded(v) => match &other.end {
|
|
|
|
Bound::Excluded(w) => v.partial_cmp(w),
|
|
|
|
_ => Some(Ordering::Less),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ordering => ordering,
|
|
|
|
},
|
|
|
|
_ => Some(Ordering::Less),
|
|
|
|
},
|
|
|
|
Bound::Excluded(v) => match &other.beg {
|
|
|
|
Bound::Excluded(w) => match v.partial_cmp(w) {
|
|
|
|
Some(Ordering::Equal) => match &self.end {
|
|
|
|
Bound::Unbounded => match &other.end {
|
|
|
|
Bound::Unbounded => Some(Ordering::Equal),
|
|
|
|
_ => Some(Ordering::Greater),
|
|
|
|
},
|
|
|
|
Bound::Included(v) => match &other.end {
|
|
|
|
Bound::Unbounded => Some(Ordering::Less),
|
|
|
|
Bound::Included(w) => v.partial_cmp(w),
|
|
|
|
_ => Some(Ordering::Greater),
|
|
|
|
},
|
|
|
|
Bound::Excluded(v) => match &other.end {
|
|
|
|
Bound::Excluded(w) => v.partial_cmp(w),
|
|
|
|
_ => Some(Ordering::Less),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ordering => ordering,
|
|
|
|
},
|
|
|
|
_ => Some(Ordering::Greater),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ordering => ordering,
|
|
|
|
}
|
|
|
|
}
|
2022-08-28 22:19:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for Range {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2022-10-30 01:11:59 +00:00
|
|
|
write!(f, "{}:", self.tb)?;
|
|
|
|
match &self.beg {
|
|
|
|
Bound::Unbounded => write!(f, ""),
|
2023-02-03 11:47:07 +00:00
|
|
|
Bound::Included(id) => write!(f, "{id}"),
|
|
|
|
Bound::Excluded(id) => write!(f, "{id}>"),
|
2022-10-30 01:11:59 +00:00
|
|
|
}?;
|
|
|
|
match &self.end {
|
|
|
|
Bound::Unbounded => write!(f, ".."),
|
2023-02-03 11:47:07 +00:00
|
|
|
Bound::Excluded(id) => write!(f, "..{id}"),
|
|
|
|
Bound::Included(id) => write!(f, "..={id}"),
|
2022-10-30 01:11:59 +00:00
|
|
|
}?;
|
|
|
|
Ok(())
|
2022-08-28 22:19:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-30 10:41:44 +00:00
|
|
|
impl Serialize for Range {
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: serde::Serializer,
|
|
|
|
{
|
|
|
|
if is_internal_serialization() {
|
|
|
|
let mut val = serializer.serialize_struct(TOKEN, 3)?;
|
|
|
|
val.serialize_field("tb", &self.tb)?;
|
|
|
|
val.serialize_field("beg", &self.beg)?;
|
|
|
|
val.serialize_field("end", &self.end)?;
|
|
|
|
val.end()
|
|
|
|
} else {
|
|
|
|
serializer.serialize_none()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-28 22:19:59 +00:00
|
|
|
pub fn range(i: &str) -> IResult<&str, Range> {
|
|
|
|
let (i, tb) = ident_raw(i)?;
|
|
|
|
let (i, _) = char(':')(i)?;
|
2022-10-30 01:11:59 +00:00
|
|
|
let (i, beg) =
|
|
|
|
opt(alt((map(terminated(id, char('>')), Bound::Excluded), map(id, Bound::Included))))(i)?;
|
2022-08-28 22:19:59 +00:00
|
|
|
let (i, _) = char('.')(i)?;
|
|
|
|
let (i, _) = char('.')(i)?;
|
2022-10-30 01:11:59 +00:00
|
|
|
let (i, end) =
|
|
|
|
opt(alt((map(preceded(char('='), id), Bound::Included), map(id, Bound::Excluded))))(i)?;
|
2022-08-28 22:19:59 +00:00
|
|
|
Ok((
|
|
|
|
i,
|
|
|
|
Range {
|
|
|
|
tb,
|
2022-10-30 01:11:59 +00:00
|
|
|
beg: beg.unwrap_or(Bound::Unbounded),
|
|
|
|
end: end.unwrap_or(Bound::Unbounded),
|
2022-08-28 22:19:59 +00:00
|
|
|
},
|
|
|
|
))
|
|
|
|
}
|
2022-09-04 09:51:26 +00:00
|
|
|
|
2022-08-28 22:19:59 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
2022-09-04 09:51:26 +00:00
|
|
|
#[test]
|
|
|
|
fn range_int() {
|
|
|
|
let sql = "person:1..100";
|
|
|
|
let res = range(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!(r#"person:1..100"#, format!("{}", out));
|
|
|
|
}
|
|
|
|
|
2022-08-28 22:19:59 +00:00
|
|
|
#[test]
|
|
|
|
fn range_array() {
|
|
|
|
let sql = "person:['USA', 10]..['USA', 100]";
|
|
|
|
let res = range(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
2022-10-19 14:48:50 +00:00
|
|
|
assert_eq!("person:['USA', 10]..['USA', 100]", format!("{}", out));
|
2022-08-28 22:19:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn range_object() {
|
|
|
|
let sql = "person:{ country: 'USA', position: 10 }..{ country: 'USA', position: 100 }";
|
|
|
|
let res = range(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!(
|
2022-10-19 14:48:50 +00:00
|
|
|
"person:{ country: 'USA', position: 10 }..{ country: 'USA', position: 100 }",
|
2022-08-28 22:19:59 +00:00
|
|
|
format!("{}", out)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|