parent
e26d86b412
commit
c1a1eba8b5
9 changed files with 206 additions and 4 deletions
|
@ -135,6 +135,66 @@ impl Iterable {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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 next holder key
|
||||||
|
let mut nxt: Option<Vec<u8>> = None;
|
||||||
|
// Loop until no more keys
|
||||||
|
loop {
|
||||||
|
// Check if the context is finished
|
||||||
|
if ctx.is_done() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Get the next 1000 key-value entries
|
||||||
|
let res = match nxt {
|
||||||
|
None => {
|
||||||
|
let min = beg.clone();
|
||||||
|
let max = end.clone();
|
||||||
|
txn.clone().lock().await.scan(min..max, 1000).await?
|
||||||
|
}
|
||||||
|
Some(ref mut beg) => {
|
||||||
|
beg.push(0x00);
|
||||||
|
let min = beg.clone();
|
||||||
|
let max = end.clone();
|
||||||
|
txn.clone().lock().await.scan(min..max, 1000).await?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// If there are key-value entries then fetch them
|
||||||
|
if !res.is_empty() {
|
||||||
|
// Get total results
|
||||||
|
let n = res.len();
|
||||||
|
// Exit when settled
|
||||||
|
if n == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Loop over results
|
||||||
|
for (i, (k, v)) in res.into_iter().enumerate() {
|
||||||
|
// Check the context
|
||||||
|
if ctx.is_done() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Ready the next
|
||||||
|
if n == i + 1 {
|
||||||
|
nxt = Some(k.clone());
|
||||||
|
}
|
||||||
|
// Parse the data from the store
|
||||||
|
let key: crate::key::thing::Thing = (&k).into();
|
||||||
|
let val: crate::sql::value::Value = (&v).into();
|
||||||
|
let rid = Thing::from((key.tb, key.id));
|
||||||
|
// Create a new operable value
|
||||||
|
let val = Operable::Value(val);
|
||||||
|
// Process the record
|
||||||
|
chn.send((Some(rid), val)).await?;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
Iterable::Edges(e) => {
|
Iterable::Edges(e) => {
|
||||||
// Pull out options
|
// Pull out options
|
||||||
let ns = opt.ns();
|
let ns = opt.ns();
|
||||||
|
|
|
@ -135,6 +135,66 @@ impl Iterable {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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 next holder key
|
||||||
|
let mut nxt: Option<Vec<u8>> = None;
|
||||||
|
// Loop until no more keys
|
||||||
|
loop {
|
||||||
|
// Check if the context is finished
|
||||||
|
if ctx.is_done() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Get the next 1000 key-value entries
|
||||||
|
let res = match nxt {
|
||||||
|
None => {
|
||||||
|
let min = beg.clone();
|
||||||
|
let max = end.clone();
|
||||||
|
txn.clone().lock().await.scan(min..max, 1000).await?
|
||||||
|
}
|
||||||
|
Some(ref mut beg) => {
|
||||||
|
beg.push(0x00);
|
||||||
|
let min = beg.clone();
|
||||||
|
let max = end.clone();
|
||||||
|
txn.clone().lock().await.scan(min..max, 1000).await?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// If there are key-value entries then fetch them
|
||||||
|
if !res.is_empty() {
|
||||||
|
// Get total results
|
||||||
|
let n = res.len();
|
||||||
|
// Exit when settled
|
||||||
|
if n == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Loop over results
|
||||||
|
for (i, (k, v)) in res.into_iter().enumerate() {
|
||||||
|
// Check the context
|
||||||
|
if ctx.is_done() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Ready the next
|
||||||
|
if n == i + 1 {
|
||||||
|
nxt = Some(k.clone());
|
||||||
|
}
|
||||||
|
// Parse the data from the store
|
||||||
|
let key: crate::key::thing::Thing = (&k).into();
|
||||||
|
let val: crate::sql::value::Value = (&v).into();
|
||||||
|
let rid = Thing::from((key.tb, key.id));
|
||||||
|
// Create a new operable value
|
||||||
|
let val = Operable::Value(val);
|
||||||
|
// Process the record
|
||||||
|
ite.process(ctx, opt, txn, stm, Some(rid), val).await;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
Iterable::Edges(e) => {
|
Iterable::Edges(e) => {
|
||||||
// Pull out options
|
// Pull out options
|
||||||
let ns = opt.ns();
|
let ns = opt.ns();
|
||||||
|
|
|
@ -10,6 +10,7 @@ use crate::sql::array::Array;
|
||||||
use crate::sql::edges::Edges;
|
use crate::sql::edges::Edges;
|
||||||
use crate::sql::field::Field;
|
use crate::sql::field::Field;
|
||||||
use crate::sql::part::Part;
|
use crate::sql::part::Part;
|
||||||
|
use crate::sql::range::Range;
|
||||||
use crate::sql::table::Table;
|
use crate::sql::table::Table;
|
||||||
use crate::sql::thing::Thing;
|
use crate::sql::thing::Thing;
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
|
@ -22,6 +23,7 @@ pub enum Iterable {
|
||||||
Value(Value),
|
Value(Value),
|
||||||
Table(Table),
|
Table(Table),
|
||||||
Thing(Thing),
|
Thing(Thing),
|
||||||
|
Range(Range),
|
||||||
Edges(Edges),
|
Edges(Edges),
|
||||||
Mergeable(Thing, Value),
|
Mergeable(Thing, Value),
|
||||||
Relatable(Thing, Thing, Thing),
|
Relatable(Thing, Thing, Thing),
|
||||||
|
|
|
@ -37,6 +37,7 @@ pub(crate) mod part;
|
||||||
pub(crate) mod paths;
|
pub(crate) mod paths;
|
||||||
pub(crate) mod permission;
|
pub(crate) mod permission;
|
||||||
pub(crate) mod query;
|
pub(crate) mod query;
|
||||||
|
pub(crate) mod range;
|
||||||
pub(crate) mod regex;
|
pub(crate) mod regex;
|
||||||
pub(crate) mod script;
|
pub(crate) mod script;
|
||||||
pub(crate) mod serde;
|
pub(crate) mod serde;
|
||||||
|
@ -100,6 +101,7 @@ pub use self::part::Part;
|
||||||
pub use self::permission::Permission;
|
pub use self::permission::Permission;
|
||||||
pub use self::permission::Permissions;
|
pub use self::permission::Permissions;
|
||||||
pub use self::query::Query;
|
pub use self::query::Query;
|
||||||
|
pub use self::range::Range;
|
||||||
pub use self::regex::Regex;
|
pub use self::regex::Regex;
|
||||||
pub use self::script::Script;
|
pub use self::script::Script;
|
||||||
pub use self::split::Split;
|
pub use self::split::Split;
|
||||||
|
|
62
lib/src/sql/range.rs
Normal file
62
lib/src/sql/range.rs
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
use crate::sql::error::IResult;
|
||||||
|
use crate::sql::id::{id, Id};
|
||||||
|
use crate::sql::ident::ident_raw;
|
||||||
|
use nom::character::complete::char;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||||
|
pub struct Range {
|
||||||
|
pub tb: String,
|
||||||
|
pub beg: Id,
|
||||||
|
pub end: Id,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Range {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}:{}..{}", self.tb, self.beg, self.end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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, _) = char('.')(i)?;
|
||||||
|
let (i, _) = char('.')(i)?;
|
||||||
|
let (i, end) = id(i)?;
|
||||||
|
Ok((
|
||||||
|
i,
|
||||||
|
Range {
|
||||||
|
tb,
|
||||||
|
beg,
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn range_array() {
|
||||||
|
let sql = "person:['USA', 10]..['USA', 100]";
|
||||||
|
let res = range(sql);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
let out = res.unwrap().1;
|
||||||
|
assert_eq!(r#"person:["USA", 10]..["USA", 100]"#, format!("{}", out));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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!(
|
||||||
|
r#"person:{ country: "USA", position: 10 }..{ country: "USA", position: 100 }"#,
|
||||||
|
format!("{}", out)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -55,6 +55,7 @@ impl DeleteStatement {
|
||||||
match v {
|
match v {
|
||||||
Value::Table(v) => i.ingest(Iterable::Table(v)),
|
Value::Table(v) => i.ingest(Iterable::Table(v)),
|
||||||
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
|
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
|
||||||
|
Value::Range(v) => i.ingest(Iterable::Range(*v)),
|
||||||
Value::Edges(v) => i.ingest(Iterable::Edges(*v)),
|
Value::Edges(v) => i.ingest(Iterable::Edges(*v)),
|
||||||
Value::Model(v) => {
|
Value::Model(v) => {
|
||||||
for v in v {
|
for v in v {
|
||||||
|
|
|
@ -94,6 +94,7 @@ impl SelectStatement {
|
||||||
match v {
|
match v {
|
||||||
Value::Table(v) => i.ingest(Iterable::Table(v)),
|
Value::Table(v) => i.ingest(Iterable::Table(v)),
|
||||||
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
|
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
|
||||||
|
Value::Range(v) => i.ingest(Iterable::Range(*v)),
|
||||||
Value::Edges(v) => i.ingest(Iterable::Edges(*v)),
|
Value::Edges(v) => i.ingest(Iterable::Edges(*v)),
|
||||||
Value::Model(v) => {
|
Value::Model(v) => {
|
||||||
for v in v {
|
for v in v {
|
||||||
|
|
|
@ -56,6 +56,7 @@ impl UpdateStatement {
|
||||||
match v {
|
match v {
|
||||||
Value::Table(v) => i.ingest(Iterable::Table(v)),
|
Value::Table(v) => i.ingest(Iterable::Table(v)),
|
||||||
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
|
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
|
||||||
|
Value::Range(v) => i.ingest(Iterable::Range(*v)),
|
||||||
Value::Edges(v) => i.ingest(Iterable::Edges(*v)),
|
Value::Edges(v) => i.ingest(Iterable::Edges(*v)),
|
||||||
Value::Model(v) => {
|
Value::Model(v) => {
|
||||||
for v in v {
|
for v in v {
|
||||||
|
|
|
@ -23,6 +23,7 @@ use crate::sql::object::{object, Object};
|
||||||
use crate::sql::operation::Operation;
|
use crate::sql::operation::Operation;
|
||||||
use crate::sql::param::{param, Param};
|
use crate::sql::param::{param, Param};
|
||||||
use crate::sql::part::Part;
|
use crate::sql::part::Part;
|
||||||
|
use crate::sql::range::{range, Range};
|
||||||
use crate::sql::regex::{regex, Regex};
|
use crate::sql::regex::{regex, Regex};
|
||||||
use crate::sql::serde::is_internal_serialization;
|
use crate::sql::serde::is_internal_serialization;
|
||||||
use crate::sql::strand::{strand, Strand};
|
use crate::sql::strand::{strand, Strand};
|
||||||
|
@ -114,6 +115,7 @@ pub enum Value {
|
||||||
Thing(Thing),
|
Thing(Thing),
|
||||||
Model(Model),
|
Model(Model),
|
||||||
Regex(Regex),
|
Regex(Regex),
|
||||||
|
Range(Box<Range>),
|
||||||
Edges(Box<Edges>),
|
Edges(Box<Edges>),
|
||||||
Function(Box<Function>),
|
Function(Box<Function>),
|
||||||
Subquery(Box<Subquery>),
|
Subquery(Box<Subquery>),
|
||||||
|
@ -227,6 +229,12 @@ impl From<Duration> for Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Range> for Value {
|
||||||
|
fn from(v: Range) -> Self {
|
||||||
|
Value::Range(Box::new(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Edges> for Value {
|
impl From<Edges> for Value {
|
||||||
fn from(v: Edges) -> Self {
|
fn from(v: Edges) -> Self {
|
||||||
Value::Edges(Box::new(v))
|
Value::Edges(Box::new(v))
|
||||||
|
@ -1071,6 +1079,7 @@ impl fmt::Display for Value {
|
||||||
Value::Thing(v) => write!(f, "{}", v),
|
Value::Thing(v) => write!(f, "{}", v),
|
||||||
Value::Model(v) => write!(f, "{}", v),
|
Value::Model(v) => write!(f, "{}", v),
|
||||||
Value::Regex(v) => write!(f, "{}", v),
|
Value::Regex(v) => write!(f, "{}", v),
|
||||||
|
Value::Range(v) => write!(f, "{}", v),
|
||||||
Value::Edges(v) => write!(f, "{}", v),
|
Value::Edges(v) => write!(f, "{}", v),
|
||||||
Value::Function(v) => write!(f, "{}", v),
|
Value::Function(v) => write!(f, "{}", v),
|
||||||
Value::Subquery(v) => write!(f, "{}", v),
|
Value::Subquery(v) => write!(f, "{}", v),
|
||||||
|
@ -1142,10 +1151,11 @@ impl Serialize for Value {
|
||||||
Value::Thing(v) => s.serialize_newtype_variant("Value", 15, "Thing", v),
|
Value::Thing(v) => s.serialize_newtype_variant("Value", 15, "Thing", v),
|
||||||
Value::Model(v) => s.serialize_newtype_variant("Value", 16, "Model", v),
|
Value::Model(v) => s.serialize_newtype_variant("Value", 16, "Model", v),
|
||||||
Value::Regex(v) => s.serialize_newtype_variant("Value", 17, "Regex", v),
|
Value::Regex(v) => s.serialize_newtype_variant("Value", 17, "Regex", v),
|
||||||
Value::Edges(v) => s.serialize_newtype_variant("Value", 18, "Edges", v),
|
Value::Range(v) => s.serialize_newtype_variant("Value", 18, "Range", v),
|
||||||
Value::Function(v) => s.serialize_newtype_variant("Value", 19, "Function", v),
|
Value::Edges(v) => s.serialize_newtype_variant("Value", 19, "Edges", v),
|
||||||
Value::Subquery(v) => s.serialize_newtype_variant("Value", 20, "Subquery", v),
|
Value::Function(v) => s.serialize_newtype_variant("Value", 20, "Function", v),
|
||||||
Value::Expression(v) => s.serialize_newtype_variant("Value", 21, "Expression", v),
|
Value::Subquery(v) => s.serialize_newtype_variant("Value", 21, "Subquery", v),
|
||||||
|
Value::Expression(v) => s.serialize_newtype_variant("Value", 22, "Expression", v),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match self {
|
match self {
|
||||||
|
@ -1275,6 +1285,7 @@ pub fn select(i: &str) -> IResult<&str, Value> {
|
||||||
map(regex, Value::from),
|
map(regex, Value::from),
|
||||||
map(model, Value::from),
|
map(model, Value::from),
|
||||||
map(edges, Value::from),
|
map(edges, Value::from),
|
||||||
|
map(range, Value::from),
|
||||||
map(thing, Value::from),
|
map(thing, Value::from),
|
||||||
map(table, Value::from),
|
map(table, Value::from),
|
||||||
map(strand, Value::from),
|
map(strand, Value::from),
|
||||||
|
@ -1289,6 +1300,7 @@ pub fn what(i: &str) -> IResult<&str, Value> {
|
||||||
map(param, Value::from),
|
map(param, Value::from),
|
||||||
map(model, Value::from),
|
map(model, Value::from),
|
||||||
map(edges, Value::from),
|
map(edges, Value::from),
|
||||||
|
map(range, Value::from),
|
||||||
map(thing, Value::from),
|
map(thing, Value::from),
|
||||||
map(table, Value::from),
|
map(table, Value::from),
|
||||||
))(i)
|
))(i)
|
||||||
|
@ -1472,6 +1484,7 @@ mod tests {
|
||||||
assert_eq!(56, std::mem::size_of::<crate::sql::thing::Thing>());
|
assert_eq!(56, std::mem::size_of::<crate::sql::thing::Thing>());
|
||||||
assert_eq!(48, std::mem::size_of::<crate::sql::model::Model>());
|
assert_eq!(48, std::mem::size_of::<crate::sql::model::Model>());
|
||||||
assert_eq!(24, std::mem::size_of::<crate::sql::regex::Regex>());
|
assert_eq!(24, std::mem::size_of::<crate::sql::regex::Regex>());
|
||||||
|
assert_eq!(8, std::mem::size_of::<Box<crate::sql::range::Range>>());
|
||||||
assert_eq!(8, std::mem::size_of::<Box<crate::sql::edges::Edges>>());
|
assert_eq!(8, std::mem::size_of::<Box<crate::sql::edges::Edges>>());
|
||||||
assert_eq!(8, std::mem::size_of::<Box<crate::sql::function::Function>>());
|
assert_eq!(8, std::mem::size_of::<Box<crate::sql::function::Function>>());
|
||||||
assert_eq!(8, std::mem::size_of::<Box<crate::sql::subquery::Subquery>>());
|
assert_eq!(8, std::mem::size_of::<Box<crate::sql::subquery::Subquery>>());
|
||||||
|
|
Loading…
Reference in a new issue