Implement inclusive and unbounded record ranges
Closes #1412 Closes #1413
This commit is contained in:
parent
82c9d7da2b
commit
12b6e04539
3 changed files with 139 additions and 14 deletions
|
@ -11,6 +11,7 @@ use crate::sql::dir::Dir;
|
|||
use crate::sql::thing::Thing;
|
||||
use crate::sql::value::Value;
|
||||
use channel::Sender;
|
||||
use std::ops::Bound;
|
||||
|
||||
impl Iterable {
|
||||
pub(crate) async fn channel(
|
||||
|
@ -138,9 +139,32 @@ impl Iterable {
|
|||
Iterable::Range(v) => {
|
||||
// Check that the table exists
|
||||
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
|
||||
// Prepare the start and end keys
|
||||
let beg = thing::new(opt.ns(), opt.db(), &v.tb, &v.beg).encode().unwrap();
|
||||
let end = thing::new(opt.ns(), opt.db(), &v.tb, &v.end).encode().unwrap();
|
||||
// Prepare the range start key
|
||||
let beg = match &v.beg {
|
||||
Bound::Unbounded => thing::prefix(opt.ns(), opt.db(), &v.tb),
|
||||
Bound::Included(id) => {
|
||||
thing::new(opt.ns(), opt.db(), &v.tb, id).encode().unwrap()
|
||||
}
|
||||
Bound::Excluded(id) => {
|
||||
let mut key =
|
||||
thing::new(opt.ns(), opt.db(), &v.tb, id).encode().unwrap();
|
||||
key.push(0x00);
|
||||
key
|
||||
}
|
||||
};
|
||||
// Prepare the range end key
|
||||
let end = match &v.end {
|
||||
Bound::Unbounded => thing::suffix(opt.ns(), opt.db(), &v.tb),
|
||||
Bound::Excluded(id) => {
|
||||
thing::new(opt.ns(), opt.db(), &v.tb, id).encode().unwrap()
|
||||
}
|
||||
Bound::Included(id) => {
|
||||
let mut key =
|
||||
thing::new(opt.ns(), opt.db(), &v.tb, id).encode().unwrap();
|
||||
key.push(0x00);
|
||||
key
|
||||
}
|
||||
};
|
||||
// Prepare the next holder key
|
||||
let mut nxt: Option<Vec<u8>> = None;
|
||||
// Loop until no more keys
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::key::thing;
|
|||
use crate::sql::dir::Dir;
|
||||
use crate::sql::thing::Thing;
|
||||
use crate::sql::value::Value;
|
||||
use std::ops::Bound;
|
||||
|
||||
impl Iterable {
|
||||
pub(crate) async fn iterate(
|
||||
|
@ -134,9 +135,32 @@ impl Iterable {
|
|||
Iterable::Range(v) => {
|
||||
// Check that the table exists
|
||||
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
|
||||
// Prepare the start and end keys
|
||||
let beg = thing::new(opt.ns(), opt.db(), &v.tb, &v.beg).encode().unwrap();
|
||||
let end = thing::new(opt.ns(), opt.db(), &v.tb, &v.end).encode().unwrap();
|
||||
// Prepare the range start key
|
||||
let beg = match &v.beg {
|
||||
Bound::Unbounded => thing::prefix(opt.ns(), opt.db(), &v.tb),
|
||||
Bound::Included(id) => {
|
||||
thing::new(opt.ns(), opt.db(), &v.tb, id).encode().unwrap()
|
||||
}
|
||||
Bound::Excluded(id) => {
|
||||
let mut key =
|
||||
thing::new(opt.ns(), opt.db(), &v.tb, id).encode().unwrap();
|
||||
key.push(0x00);
|
||||
key
|
||||
}
|
||||
};
|
||||
// Prepare the range end key
|
||||
let end = match &v.end {
|
||||
Bound::Unbounded => thing::suffix(opt.ns(), opt.db(), &v.tb),
|
||||
Bound::Excluded(id) => {
|
||||
thing::new(opt.ns(), opt.db(), &v.tb, id).encode().unwrap()
|
||||
}
|
||||
Bound::Included(id) => {
|
||||
let mut key =
|
||||
thing::new(opt.ns(), opt.db(), &v.tb, id).encode().unwrap();
|
||||
key.push(0x00);
|
||||
key
|
||||
}
|
||||
};
|
||||
// Prepare the next holder key
|
||||
let mut nxt: Option<Vec<u8>> = None;
|
||||
// Loop until no more keys
|
||||
|
|
|
@ -1,36 +1,113 @@
|
|||
use crate::sql::error::IResult;
|
||||
use crate::sql::id::{id, Id};
|
||||
use crate::sql::ident::ident_raw;
|
||||
use nom::branch::alt;
|
||||
use nom::character::complete::char;
|
||||
use nom::combinator::map;
|
||||
use nom::combinator::opt;
|
||||
use nom::sequence::preceded;
|
||||
use nom::sequence::terminated;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
use std::ops::Bound;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
|
||||
pub struct Range {
|
||||
pub tb: String,
|
||||
pub beg: Id,
|
||||
pub end: Id,
|
||||
pub beg: Bound<Id>,
|
||||
pub end: Bound<Id>,
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Range {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}:{}..{}", self.tb, self.beg, self.end)
|
||||
write!(f, "{}:", self.tb)?;
|
||||
match &self.beg {
|
||||
Bound::Unbounded => write!(f, ""),
|
||||
Bound::Included(id) => write!(f, "{}", id),
|
||||
Bound::Excluded(id) => write!(f, "{}>", id),
|
||||
}?;
|
||||
match &self.end {
|
||||
Bound::Unbounded => write!(f, ".."),
|
||||
Bound::Excluded(id) => write!(f, "..{}", id),
|
||||
Bound::Included(id) => write!(f, "..={}", id),
|
||||
}?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn range(i: &str) -> IResult<&str, Range> {
|
||||
let (i, tb) = ident_raw(i)?;
|
||||
let (i, _) = char(':')(i)?;
|
||||
let (i, beg) = id(i)?;
|
||||
let (i, beg) =
|
||||
opt(alt((map(terminated(id, char('>')), Bound::Excluded), map(id, Bound::Included))))(i)?;
|
||||
let (i, _) = char('.')(i)?;
|
||||
let (i, _) = char('.')(i)?;
|
||||
let (i, end) = id(i)?;
|
||||
let (i, end) =
|
||||
opt(alt((map(preceded(char('='), id), Bound::Included), map(id, Bound::Excluded))))(i)?;
|
||||
Ok((
|
||||
i,
|
||||
Range {
|
||||
tb,
|
||||
beg,
|
||||
end,
|
||||
beg: beg.unwrap_or(Bound::Unbounded),
|
||||
end: end.unwrap_or(Bound::Unbounded),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue