change number representation

main
Ziyang Hu 2 years ago
parent 8150e3573e
commit ee5d60817c

@ -26,7 +26,7 @@ rmp-serde = "1.1.0"
rmpv = "1.0.0"
base64 = "0.13.0"
chrono = "0.4.19"
ordered-float = { version = "3.0", features = ["serde"] }
num-traits = "0.2.15"
itertools = "0.10.3"
pest = "2.2.1"
pest_derive = "2.2.1"

@ -12,5 +12,3 @@
* [x] public API
* [x] sorting
* [ ] range scan
comparators can have problems when sorting mixed integers and floats

@ -1,9 +1,9 @@
use std::cmp::{max, min};
use std::cmp::{max, min, Ordering};
use std::fmt::{Debug, Formatter};
use anyhow::{bail, Result};
use crate::data::value::DataValue;
use crate::data::value::{DataValue, Number};
#[derive(Clone)]
pub(crate) struct Aggregation {
@ -37,10 +37,12 @@ macro_rules! define_aggr {
define_aggr!(AGGR_COUNT, false);
fn aggr_count(accum: &DataValue, current: &DataValue) -> Result<DataValue> {
match (accum, current) {
(DataValue::Guard, DataValue::Guard) => Ok(DataValue::Int(0)),
(DataValue::Guard, _) => Ok(DataValue::Int(1)),
(DataValue::Int(i), DataValue::Guard) => Ok(DataValue::Int(*i)),
(DataValue::Int(i), _) => Ok(DataValue::Int(*i + 1)),
(DataValue::Guard, DataValue::Guard) => Ok(DataValue::Number(Number::Int(0))),
(DataValue::Guard, _) => Ok(DataValue::Number(Number::Int(1))),
(DataValue::Number(Number::Int(i)), DataValue::Guard) => {
Ok(DataValue::Number(Number::Int(*i)))
}
(DataValue::Number(Number::Int(i)), _) => Ok(DataValue::Number(Number::Int(*i + 1))),
_ => unreachable!(),
}
}
@ -48,16 +50,29 @@ fn aggr_count(accum: &DataValue, current: &DataValue) -> Result<DataValue> {
define_aggr!(AGGR_SUM, false);
fn aggr_sum(accum: &DataValue, current: &DataValue) -> Result<DataValue> {
match (accum, current) {
(DataValue::Guard, DataValue::Guard) => Ok(DataValue::Int(0)),
(DataValue::Guard, DataValue::Int(i)) => Ok(DataValue::Int(*i)),
(DataValue::Guard, DataValue::Float(f)) => Ok(DataValue::Float(f.0.into())),
(DataValue::Int(i), DataValue::Guard) => Ok(DataValue::Int(*i)),
(DataValue::Float(f), DataValue::Guard) => Ok(DataValue::Float(f.0.into())),
(DataValue::Int(i), DataValue::Int(j)) => Ok(DataValue::Int(*i + *j)),
(DataValue::Int(j), DataValue::Float(i)) | (DataValue::Float(i), DataValue::Int(j)) => {
Ok(DataValue::Float((i.0 + (*j as f64)).into()))
}
(DataValue::Float(i), DataValue::Float(j)) => Ok(DataValue::Float((i.0 + j.0).into())),
(DataValue::Guard, DataValue::Guard) => Ok(DataValue::Number(Number::Int(0))),
(DataValue::Guard, DataValue::Number(Number::Int(i))) => {
Ok(DataValue::Number(Number::Int(*i)))
}
(DataValue::Guard, DataValue::Number(Number::Float(f))) => {
Ok(DataValue::Number(Number::Float(*f)))
}
(DataValue::Number(Number::Int(i)), DataValue::Guard) => {
Ok(DataValue::Number(Number::Int(*i)))
}
(DataValue::Number(Number::Float(f)), DataValue::Guard) => {
Ok(DataValue::Number(Number::Float(*f)))
}
(DataValue::Number(Number::Int(i)), DataValue::Number(Number::Int(j))) => {
Ok(DataValue::Number(Number::Int(*i + *j)))
}
(DataValue::Number(Number::Int(j)), DataValue::Number(Number::Float(i)))
| (DataValue::Number(Number::Float(i)), DataValue::Number(Number::Int(j))) => {
Ok(DataValue::Number(Number::Float(*i + (*j as f64))))
}
(DataValue::Number(Number::Float(i)), DataValue::Number(Number::Float(j))) => {
Ok(DataValue::Number(Number::Float(*i + *j)))
}
(i, j) => bail!(
"cannot compute min: encountered value {:?} for aggregate {:?}",
j,
@ -69,14 +84,31 @@ fn aggr_sum(accum: &DataValue, current: &DataValue) -> Result<DataValue> {
define_aggr!(AGGR_MIN, true);
fn aggr_min(accum: &DataValue, current: &DataValue) -> Result<DataValue> {
match (accum, current) {
(DataValue::Guard, DataValue::Int(i)) => Ok(DataValue::Int(*i)),
(DataValue::Guard, DataValue::Float(f)) => Ok(DataValue::Float(f.0.into())),
(DataValue::Int(i), DataValue::Int(j)) => Ok(DataValue::Int(min(*i, *j))),
(DataValue::Int(j), DataValue::Float(i)) | (DataValue::Float(i), DataValue::Int(j)) => {
Ok(DataValue::Float(min(i.clone(), (*j as f64).into())))
(DataValue::Guard, DataValue::Number(Number::Int(i))) => {
Ok(DataValue::Number(Number::Int(*i)))
}
(DataValue::Float(i), DataValue::Float(j)) => {
Ok(DataValue::Float(min(i.clone(), j.clone())))
(DataValue::Guard, DataValue::Number(Number::Float(f))) => {
Ok(DataValue::Number(Number::Float(*f)))
}
(DataValue::Number(Number::Int(i)), DataValue::Number(Number::Int(j))) => {
Ok(DataValue::Number(Number::Int(min(*i, *j))))
}
(DataValue::Number(Number::Int(j)), DataValue::Number(Number::Float(i)))
| (DataValue::Number(Number::Float(i)), DataValue::Number(Number::Int(j))) => {
let m = match i.total_cmp(&(*j as f64)) {
Ordering::Less => *i,
Ordering::Equal => *i,
Ordering::Greater => *j as f64,
};
Ok(DataValue::Number(Number::Float(m)))
}
(DataValue::Number(Number::Float(i)), DataValue::Number(Number::Float(j))) => {
let m = match i.total_cmp(j) {
Ordering::Less => *i,
Ordering::Equal => *i,
Ordering::Greater => *j,
};
Ok(DataValue::Number(Number::Float(m)))
}
(i, j) => bail!(
"cannot compute min: encountered value {:?} for aggregate {:?}",
@ -89,15 +121,34 @@ fn aggr_min(accum: &DataValue, current: &DataValue) -> Result<DataValue> {
define_aggr!(AGGR_MAX, true);
fn aggr_max(accum: &DataValue, current: &DataValue) -> Result<DataValue> {
match (accum, current) {
(DataValue::Guard, DataValue::Int(i)) => Ok(DataValue::Int(*i)),
(DataValue::Guard, DataValue::Float(f)) => Ok(DataValue::Float(f.0.into())),
(DataValue::Float(f), DataValue::Guard) => Ok(DataValue::Float(f.0.into())),
(DataValue::Int(i), DataValue::Int(j)) => Ok(DataValue::Int(max(*i, *j))),
(DataValue::Int(j), DataValue::Float(i)) | (DataValue::Float(i), DataValue::Int(j)) => {
Ok(DataValue::Float(max(i.clone(), (*j as f64).into())))
}
(DataValue::Float(i), DataValue::Float(j)) => {
Ok(DataValue::Float(max(i.clone(), j.clone())))
(DataValue::Guard, DataValue::Number(Number::Int(i))) => {
Ok(DataValue::Number(Number::Int(*i)))
}
(DataValue::Guard, DataValue::Number(Number::Float(f))) => {
Ok(DataValue::Number(Number::Float(*f)))
}
(DataValue::Number(Number::Float(f)), DataValue::Guard) => {
Ok(DataValue::Number(Number::Float(*f)))
}
(DataValue::Number(Number::Int(i)), DataValue::Number(Number::Int(j))) => {
Ok(DataValue::Number(Number::Int(max(*i, *j))))
}
(DataValue::Number(Number::Int(j)), DataValue::Number(Number::Float(i)))
| (DataValue::Number(Number::Float(i)), DataValue::Number(Number::Int(j))) => {
let m = match i.total_cmp(&(*j as f64)) {
Ordering::Less => *j as f64,
Ordering::Equal => *i,
Ordering::Greater => *i,
};
Ok(DataValue::Number(Number::Float(m)))
}
(DataValue::Number(Number::Float(i)), DataValue::Number(Number::Float(j))) => {
let m = match i.total_cmp(j) {
Ordering::Less => *j,
Ordering::Equal => *i,
Ordering::Greater => *i,
};
Ok(DataValue::Number(Number::Float(m)))
}
(i, j) => bail!(
"cannot compute min: encountered value {:?} for aggregate {:?}",

@ -12,7 +12,7 @@ use crate::data::id::{AttrId, TxId};
use crate::data::json::JsonValue;
use crate::data::symb::Symbol;
use crate::data::triple::StoreOp;
use crate::data::value::DataValue;
use crate::data::value::{DataValue, Number};
use crate::parse::triple::TempIdCtx;
#[repr(u8)]
@ -116,7 +116,7 @@ impl AttributeTyping {
pub(crate) fn coerce_value(&self, val: DataValue) -> Result<DataValue> {
match self {
AttributeTyping::Ref | AttributeTyping::Component => match val {
DataValue::Int(s) if s > 0 => Ok(DataValue::Int(s)),
DataValue::Number(Number::Int(s)) if s > 0 => Ok(DataValue::Number(Number::Int(s))),
val => Err(self.type_err(val).into()),
},
AttributeTyping::Bool => {
@ -127,15 +127,15 @@ impl AttributeTyping {
}
}
AttributeTyping::Int => {
if matches!(val, DataValue::Int(_)) {
if matches!(val, DataValue::Number(Number::Int(_))) {
Ok(val)
} else {
Err(self.type_err(val).into())
}
}
AttributeTyping::Float => match val {
v @ DataValue::Float(_) => Ok(v),
DataValue::Int(i) => Ok(DataValue::Float((i as f64).into())),
v @ DataValue::Number(Number::Float(_)) => Ok(v),
DataValue::Number(Number::Int(i)) => Ok(DataValue::Number(Number::Float(i as f64))),
val => Err(self.type_err(val).into()),
},
AttributeTyping::String => {
@ -154,7 +154,7 @@ impl AttributeTyping {
}
AttributeTyping::Timestamp => match val {
val @ DataValue::Timestamp(_) => Ok(val),
DataValue::Int(i) => Ok(DataValue::Timestamp(i)),
DataValue::Number(Number::Int(i)) => Ok(DataValue::Timestamp(i)),
val => Err(self.type_err(val).into()),
},
AttributeTyping::Bytes => {

@ -5,11 +5,10 @@ use std::ops::Rem;
use anyhow::{bail, Result};
use itertools::Itertools;
use ordered_float::{Float, OrderedFloat};
use crate::data::symb::Symbol;
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::data::value::{DataValue, Number};
#[derive(Debug, Clone)]
pub(crate) enum Expr {
@ -139,38 +138,22 @@ fn op_neq(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_GT, 2, false, true);
fn op_gt(args: &[DataValue]) -> Result<DataValue> {
Ok(DataValue::Bool(match (&args[0], &args[1]) {
(DataValue::Int(a), DataValue::Float(b)) => OrderedFloat(*a as f64) > *b,
(DataValue::Float(a), DataValue::Int(b)) => *a > OrderedFloat(*b as f64),
(_, _) => args[0] > args[1],
}))
Ok(DataValue::Bool(args[0] > args[1]))
}
define_op!(OP_GE, 2, false, true);
fn op_ge(args: &[DataValue]) -> Result<DataValue> {
Ok(DataValue::Bool(match (&args[0], &args[1]) {
(DataValue::Int(a), DataValue::Float(b)) => OrderedFloat(*a as f64) >= *b,
(DataValue::Float(a), DataValue::Int(b)) => *a >= OrderedFloat(*b as f64),
(_, _) => args[0] >= args[1],
}))
Ok(DataValue::Bool(args[0] >= args[1]))
}
define_op!(OP_LT, 2, false, true);
fn op_lt(args: &[DataValue]) -> Result<DataValue> {
Ok(DataValue::Bool(match (&args[0], &args[1]) {
(DataValue::Int(a), DataValue::Float(b)) => OrderedFloat(*a as f64) < *b,
(DataValue::Float(a), DataValue::Int(b)) => *a < OrderedFloat(*b as f64),
(_, _) => args[0] < args[1],
}))
Ok(DataValue::Bool(args[0] < args[1]))
}
define_op!(OP_LE, 2, false, true);
fn op_le(args: &[DataValue]) -> Result<DataValue> {
Ok(DataValue::Bool(match (&args[0], &args[1]) {
(DataValue::Int(a), DataValue::Float(b)) => OrderedFloat(*a as f64) <= *b,
(DataValue::Float(a), DataValue::Int(b)) => *a <= OrderedFloat(*b as f64),
(_, _) => args[0] <= args[1],
}))
Ok(DataValue::Bool(args[0] <= args[1]))
}
define_op!(OP_ADD, 0, true, false);
@ -179,15 +162,15 @@ fn op_add(args: &[DataValue]) -> Result<DataValue> {
let mut f_accum = 0.0f64;
for arg in args {
match arg {
DataValue::Int(i) => i_accum += i,
DataValue::Float(f) => f_accum += f.0,
DataValue::Number(Number::Int(i)) => i_accum += i,
DataValue::Number(Number::Float(f)) => f_accum += f,
v => bail!("unexpected arg {:?} for OP_ADD", v),
}
}
if f_accum == 0.0f64 {
Ok(DataValue::Int(i_accum))
Ok(DataValue::Number(Number::Int(i_accum)))
} else {
Ok(DataValue::Float((i_accum as f64 + f_accum).into()))
Ok(DataValue::Number(Number::Float(i_accum as f64 + f_accum)))
}
}
@ -196,22 +179,14 @@ fn op_max(args: &[DataValue]) -> Result<DataValue> {
let res = args
.iter()
.try_fold(None, |accum, nxt| match (accum, nxt) {
(None, d @ DataValue::Int(_)) => Ok(Some(d.clone())),
(None, d @ DataValue::Float(_)) => Ok(Some(d.clone())),
(Some(DataValue::Int(a)), DataValue::Int(b)) => Ok(Some(DataValue::Int(a.max(*b)))),
(Some(DataValue::Int(a)), DataValue::Float(b)) => {
Ok(Some(DataValue::Float(b.0.max(a as f64).into())))
}
(Some(DataValue::Float(a)), DataValue::Int(b)) => {
Ok(Some(DataValue::Float(a.0.max(*b as f64).into())))
}
(Some(DataValue::Float(a)), DataValue::Float(b)) => {
Ok(Some(DataValue::Float(a.0.max(b.0).into())))
(None, d @ DataValue::Number(_)) => Ok(Some(d.clone())),
(Some(DataValue::Number(a)), DataValue::Number(b)) => {
Ok(Some(DataValue::Number(a.max(*b))))
}
v => bail!("unexpected arg {:?} for OP_MAX", v),
})?;
match res {
None => Ok(DataValue::Float(f64::neg_infinity().into())),
None => Ok(DataValue::Number(Number::Float(f64::NEG_INFINITY))),
Some(v) => Ok(v),
}
}
@ -221,22 +196,14 @@ fn op_min(args: &[DataValue]) -> Result<DataValue> {
let res = args
.iter()
.try_fold(None, |accum, nxt| match (accum, nxt) {
(None, d @ DataValue::Int(_)) => Ok(Some(d.clone())),
(None, d @ DataValue::Float(_)) => Ok(Some(d.clone())),
(Some(DataValue::Int(a)), DataValue::Int(b)) => Ok(Some(DataValue::Int(a.min(*b)))),
(Some(DataValue::Int(a)), DataValue::Float(b)) => {
Ok(Some(DataValue::Float(b.0.min(a as f64).into())))
}
(Some(DataValue::Float(a)), DataValue::Int(b)) => {
Ok(Some(DataValue::Float(a.0.min(*b as f64).into())))
}
(Some(DataValue::Float(a)), DataValue::Float(b)) => {
Ok(Some(DataValue::Float(a.0.min(b.0).into())))
(None, d @ DataValue::Number(_)) => Ok(Some(d.clone())),
(Some(DataValue::Number(a)), DataValue::Number(b)) => {
Ok(Some(DataValue::Number(a.min(*b))))
}
v => bail!("unexpected arg {:?} for OP_MIN", v),
})?;
match res {
None => Ok(DataValue::Float(f64::infinity().into())),
None => Ok(DataValue::Number(Number::Float(f64::INFINITY))),
Some(v) => Ok(v),
}
}
@ -244,10 +211,18 @@ fn op_min(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_SUB, 2, false, false);
fn op_sub(args: &[DataValue]) -> Result<DataValue> {
Ok(match (&args[0], &args[1]) {
(DataValue::Int(a), DataValue::Int(b)) => DataValue::Int(*a - *b),
(DataValue::Float(a), DataValue::Float(b)) => DataValue::Float(*a - *b),
(DataValue::Int(a), DataValue::Float(b)) => DataValue::Float(((*a as f64) - b.0).into()),
(DataValue::Float(a), DataValue::Int(b)) => DataValue::Float((a.0 - (*b as f64)).into()),
(DataValue::Number(Number::Int(a)), DataValue::Number(Number::Int(b))) => {
DataValue::Number(Number::Int(*a - *b))
}
(DataValue::Number(Number::Float(a)), DataValue::Number(Number::Float(b))) => {
DataValue::Number(Number::Float(*a - *b))
}
(DataValue::Number(Number::Int(a)), DataValue::Number(Number::Float(b))) => {
DataValue::Number(Number::Float((*a as f64) - b))
}
(DataValue::Number(Number::Float(a)), DataValue::Number(Number::Int(b))) => {
DataValue::Number(Number::Float(a - (*b as f64)))
}
v => bail!("unexpected arg {:?} for OP_SUB", v),
})
}
@ -258,27 +233,33 @@ fn op_mul(args: &[DataValue]) -> Result<DataValue> {
let mut f_accum = 1.0f64;
for arg in args {
match arg {
DataValue::Int(i) => i_accum *= i,
DataValue::Float(f) => f_accum *= f.0,
DataValue::Number(Number::Int(i)) => i_accum *= i,
DataValue::Number(Number::Float(f)) => f_accum *= f,
v => bail!("unexpected arg {:?} for OP_MUL", v),
}
}
if f_accum == 1.0f64 {
Ok(DataValue::Int(i_accum))
Ok(DataValue::Number(Number::Int(i_accum)))
} else {
Ok(DataValue::Float((i_accum as f64 + f_accum).into()))
Ok(DataValue::Number(Number::Float(i_accum as f64 + f_accum)))
}
}
define_op!(OP_DIV, 2, false, false);
fn op_div(args: &[DataValue]) -> Result<DataValue> {
Ok(match (&args[0], &args[1]) {
(DataValue::Int(a), DataValue::Int(b)) => {
DataValue::Float(((*a as f64) / (*b as f64)).into())
(DataValue::Number(Number::Int(a)), DataValue::Number(Number::Int(b))) => {
DataValue::Number(Number::Float((*a as f64) / (*b as f64)))
}
(DataValue::Number(Number::Float(a)), DataValue::Number(Number::Float(b))) => {
DataValue::Number(Number::Float(*a / *b))
}
(DataValue::Number(Number::Int(a)), DataValue::Number(Number::Float(b))) => {
DataValue::Number(Number::Float((*a as f64) / b))
}
(DataValue::Number(Number::Float(a)), DataValue::Number(Number::Int(b))) => {
DataValue::Number(Number::Float(a / (*b as f64)))
}
(DataValue::Float(a), DataValue::Float(b)) => DataValue::Float(*a / *b),
(DataValue::Int(a), DataValue::Float(b)) => DataValue::Float(((*a as f64) / b.0).into()),
(DataValue::Float(a), DataValue::Int(b)) => DataValue::Float((a.0 / (*b as f64)).into()),
v => bail!("unexpected arg {:?} for OP_DIV", v),
})
}
@ -286,8 +267,8 @@ fn op_div(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_MINUS, 1, false, false);
fn op_minus(args: &[DataValue]) -> Result<DataValue> {
Ok(match &args[0] {
DataValue::Int(i) => DataValue::Int(-(*i)),
DataValue::Float(f) => DataValue::Float(-(*f)),
DataValue::Number(Number::Int(i)) => DataValue::Number(Number::Int(-(*i))),
DataValue::Number(Number::Float(f)) => DataValue::Number(Number::Float(-(*f))),
v => bail!("unexpected arg {:?} for OP_MINUS", v),
})
}
@ -295,8 +276,8 @@ fn op_minus(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_ABS, 1, false, false);
fn op_abs(args: &[DataValue]) -> Result<DataValue> {
Ok(match &args[0] {
DataValue::Int(i) => DataValue::Int(i.abs()),
DataValue::Float(f) => DataValue::Float(f.abs()),
DataValue::Number(Number::Int(i)) => DataValue::Number(Number::Int(i.abs())),
DataValue::Number(Number::Float(f)) => DataValue::Number(Number::Float(f.abs())),
v => bail!("unexpected arg {:?} for OP_ABS", v),
})
}
@ -304,8 +285,8 @@ fn op_abs(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_SIGNUM, 1, false, false);
fn op_signum(args: &[DataValue]) -> Result<DataValue> {
Ok(match &args[0] {
DataValue::Int(i) => DataValue::Int(i.signum()),
DataValue::Float(f) => DataValue::Float(f.signum()),
DataValue::Number(Number::Int(i)) => DataValue::Number(Number::Int(i.signum())),
DataValue::Number(Number::Float(f)) => DataValue::Number(Number::Float(f.signum())),
v => bail!("unexpected arg {:?} for OP_SIGNUM", v),
})
}
@ -313,8 +294,8 @@ fn op_signum(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_FLOOR, 1, false, false);
fn op_floor(args: &[DataValue]) -> Result<DataValue> {
Ok(match &args[0] {
DataValue::Int(i) => DataValue::Int(*i),
DataValue::Float(f) => DataValue::Float(f.floor()),
DataValue::Number(Number::Int(i)) => DataValue::Number(Number::Int(*i)),
DataValue::Number(Number::Float(f)) => DataValue::Number(Number::Float(f.floor())),
v => bail!("unexpected arg {:?} for OP_FLOOR", v),
})
}
@ -322,8 +303,8 @@ fn op_floor(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_CEIL, 1, false, false);
fn op_ceil(args: &[DataValue]) -> Result<DataValue> {
Ok(match &args[0] {
DataValue::Int(i) => DataValue::Int(*i),
DataValue::Float(f) => DataValue::Float(f.ceil()),
DataValue::Number(Number::Int(i)) => DataValue::Number(Number::Int(*i)),
DataValue::Number(Number::Float(f)) => DataValue::Number(Number::Float(f.ceil())),
v => bail!("unexpected arg {:?} for OP_CEIL", v),
})
}
@ -331,8 +312,8 @@ fn op_ceil(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_ROUND, 1, false, false);
fn op_round(args: &[DataValue]) -> Result<DataValue> {
Ok(match &args[0] {
DataValue::Int(i) => DataValue::Int(*i),
DataValue::Float(f) => DataValue::Float(f.round()),
DataValue::Number(Number::Int(i)) => DataValue::Number(Number::Int(*i)),
DataValue::Number(Number::Float(f)) => DataValue::Number(Number::Float(f.round())),
v => bail!("unexpected arg {:?} for OP_ROUND", v),
})
}
@ -340,211 +321,219 @@ fn op_round(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_EXP, 1, false, false);
fn op_exp(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_EXP", v),
};
Ok(DataValue::Float(a.exp().into()))
Ok(DataValue::Number(Number::Float(a.exp())))
}
define_op!(OP_EXP2, 1, false, false);
fn op_exp2(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_EXP2", v),
};
Ok(DataValue::Float(a.exp2().into()))
Ok(DataValue::Number(Number::Float(a.exp2())))
}
define_op!(OP_LN, 1, false, false);
fn op_ln(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_LN", v),
};
Ok(DataValue::Float(a.ln().into()))
Ok(DataValue::Number(Number::Float(a.ln())))
}
define_op!(OP_LOG2, 1, false, false);
fn op_log2(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_LOG2", v),
};
Ok(DataValue::Float(a.log2().into()))
Ok(DataValue::Number(Number::Float(a.log2())))
}
define_op!(OP_LOG10, 1, false, false);
fn op_log10(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_LOG10", v),
};
Ok(DataValue::Float(a.log10().into()))
Ok(DataValue::Number(Number::Float(a.log10())))
}
define_op!(OP_SIN, 1, false, false);
fn op_sin(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_SIN", v),
};
Ok(DataValue::Float(a.sin().into()))
Ok(DataValue::Number(Number::Float(a.sin())))
}
define_op!(OP_COS, 1, false, false);
fn op_cos(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_COS", v),
};
Ok(DataValue::Float(a.cos().into()))
Ok(DataValue::Number(Number::Float(a.cos())))
}
define_op!(OP_TAN, 1, false, false);
fn op_tan(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_TAN", v),
};
Ok(DataValue::Float(a.tan().into()))
Ok(DataValue::Number(Number::Float(a.tan())))
}
define_op!(OP_ASIN, 1, false, false);
fn op_asin(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_ASIN", v),
};
Ok(DataValue::Float(a.asin().into()))
Ok(DataValue::Number(Number::Float(a.asin())))
}
define_op!(OP_ACOS, 1, false, false);
fn op_acos(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_ACOS", v),
};
Ok(DataValue::Float(a.acos().into()))
Ok(DataValue::Number(Number::Float(a.acos())))
}
define_op!(OP_ATAN, 1, false, false);
fn op_atan(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_ATAN", v),
};
Ok(DataValue::Float(a.atan().into()))
Ok(DataValue::Number(Number::Float(a.atan())))
}
define_op!(OP_ATAN2, 2, false, false);
fn op_atan2(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_ATAN2", v),
};
let b = match &args[1] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_ATAN2", v),
};
Ok(DataValue::Float(a.atan2(b).into()))
Ok(DataValue::Number(Number::Float(a.atan2(b))))
}
define_op!(OP_SINH, 1, false, false);
fn op_sinh(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_SINH", v),
};
Ok(DataValue::Float(a.sinh().into()))
Ok(DataValue::Number(Number::Float(a.sinh())))
}
define_op!(OP_COSH, 1, false, false);
fn op_cosh(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_COSH", v),
};
Ok(DataValue::Float(a.cosh().into()))
Ok(DataValue::Number(Number::Float(a.cosh())))
}
define_op!(OP_TANH, 1, false, false);
fn op_tanh(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_TANH", v),
};
Ok(DataValue::Float(a.tanh().into()))
Ok(DataValue::Number(Number::Float(a.tanh())))
}
define_op!(OP_ASINH, 1, false, false);
fn op_asinh(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_ASINH", v),
};
Ok(DataValue::Float(a.asinh().into()))
Ok(DataValue::Number(Number::Float(a.asinh())))
}
define_op!(OP_ACOSH, 1, false, false);
fn op_acosh(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_ACOSH", v),
};
Ok(DataValue::Float(a.acosh().into()))
Ok(DataValue::Number(Number::Float(a.acosh())))
}
define_op!(OP_ATANH, 1, false, false);
fn op_atanh(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_ATANH", v),
};
Ok(DataValue::Float(a.atanh().into()))
Ok(DataValue::Number(Number::Float(a.atanh())))
}
define_op!(OP_POW, 2, false, false);
fn op_pow(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_POW", v),
};
let b = match &args[1] {
DataValue::Int(i) => *i as f64,
DataValue::Float(f) => f.0,
DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_POW", v),
};
Ok(DataValue::Float(a.powf(b).into()))
Ok(DataValue::Number(Number::Float(a.powf(b))))
}
define_op!(OP_MOD, 2, false, false);
fn op_mod(args: &[DataValue]) -> Result<DataValue> {
Ok(match (&args[0], &args[1]) {
(DataValue::Int(a), DataValue::Int(b)) => DataValue::Int(a.rem(b)),
(DataValue::Float(a), DataValue::Float(b)) => DataValue::Float(a.rem(*b)),
(DataValue::Int(a), DataValue::Float(b)) => DataValue::Float(((*a as f64).rem(b.0)).into()),
(DataValue::Float(a), DataValue::Int(b)) => DataValue::Float((a.0.rem(*b as f64)).into()),
(DataValue::Number(Number::Int(a)), DataValue::Number(Number::Int(b))) => {
DataValue::Number(Number::Int(a.rem(b)))
}
(DataValue::Number(Number::Float(a)), DataValue::Number(Number::Float(b))) => {
DataValue::Number(Number::Float(a.rem(*b)))
}
(DataValue::Number(Number::Int(a)), DataValue::Number(Number::Float(b))) => {
DataValue::Number(Number::Float((*a as f64).rem(b)))
}
(DataValue::Number(Number::Float(a)), DataValue::Number(Number::Int(b))) => {
DataValue::Number(Number::Float(a.rem(*b as f64)))
}
v => bail!("unexpected arg {:?} for OP_MOD", v),
})
}
@ -632,19 +621,25 @@ fn op_is_null(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_IS_INT, 1, false, true);
fn op_is_int(args: &[DataValue]) -> Result<DataValue> {
Ok(DataValue::Bool(matches!(args[0], DataValue::Int(_))))
Ok(DataValue::Bool(matches!(
args[0],
DataValue::Number(Number::Int(_))
)))
}
define_op!(OP_IS_FLOAT, 1, false, true);
fn op_is_float(args: &[DataValue]) -> Result<DataValue> {
Ok(DataValue::Bool(matches!(args[0], DataValue::Float(_))))
Ok(DataValue::Bool(matches!(
args[0],
DataValue::Number(Number::Float(_))
)))
}
define_op!(OP_IS_NUM, 1, false, true);
fn op_is_num(args: &[DataValue]) -> Result<DataValue> {
Ok(DataValue::Bool(matches!(
args[0],
DataValue::Int(_) | DataValue::Float(_)
DataValue::Number(Number::Int(_)) | DataValue::Number(Number::Float(_))
)))
}

@ -90,7 +90,7 @@ impl EntityId {
pub(crate) const MAX_PERM: EntityId = EntityId(0x00ff_ffff_ff00_0000);
pub(crate) fn to_value(&self) -> DataValue {
DataValue::Int(self.0 as i64)
DataValue::from(self.0 as i64)
}
pub(crate) fn from_bytes(b: &[u8]) -> Self {

@ -5,7 +5,7 @@ pub(crate) use serde_json::Value as JsonValue;
use crate::data::attr::{Attribute, AttributeCardinality, AttributeIndex, AttributeTyping};
use crate::data::id::{AttrId, EntityId, TxId};
use crate::data::symb::Symbol;
use crate::data::value::DataValue;
use crate::data::value::{DataValue, Number};
impl From<JsonValue> for DataValue {
fn from(v: JsonValue) -> Self {
@ -13,9 +13,9 @@ impl From<JsonValue> for DataValue {
JsonValue::Null => DataValue::Null,
JsonValue::Bool(b) => DataValue::Bool(b),
JsonValue::Number(n) => match n.as_i64() {
Some(i) => DataValue::Int(i),
Some(i) => DataValue::from(i),
None => match n.as_f64() {
Some(f) => DataValue::Float(f.into()),
Some(f) => DataValue::from(f),
None => DataValue::String(n.to_string().into()),
},
},
@ -38,9 +38,9 @@ impl<'a> From<&'a JsonValue> for DataValue {
JsonValue::Null => DataValue::Null,
JsonValue::Bool(b) => DataValue::Bool(*b),
JsonValue::Number(n) => match n.as_i64() {
Some(i) => DataValue::Int(i),
Some(i) => DataValue::from(i),
None => match n.as_f64() {
Some(f) => DataValue::Float(f.into()),
Some(f) => DataValue::from(f),
None => DataValue::String(n.to_string().into()),
},
},
@ -62,8 +62,8 @@ impl From<DataValue> for JsonValue {
match v {
DataValue::Null => JsonValue::Null,
DataValue::Bool(b) => JsonValue::Bool(b),
DataValue::Int(i) => JsonValue::Number(i.into()),
DataValue::Float(f) => json!(f.0),
DataValue::Number(Number::Int(i)) => JsonValue::Number(i.into()),
DataValue::Number(Number::Float(f)) => json!(f),
DataValue::String(t) => JsonValue::String(t.into()),
DataValue::Uuid(uuid) => JsonValue::String(uuid.to_string()),
DataValue::Bytes(bytes) => JsonValue::String(base64::encode(bytes)),
@ -73,7 +73,7 @@ impl From<DataValue> for JsonValue {
DataValue::DescVal(v) => JsonValue::from(*v.0),
DataValue::Bottom => JsonValue::Null,
DataValue::Timestamp(i) => JsonValue::Number(i.into()),
DataValue::Guard => JsonValue::Null
DataValue::Guard => JsonValue::Null,
}
}
}
@ -99,18 +99,11 @@ impl TryFrom<&'_ JsonValue> for Attribute {
None => AttrId(0),
Some(v) => AttrId::try_from(v)?,
};
let name = map.get("name").ok_or_else(|| {
anyhow!(
"expect field 'name' in attribute definition, got {}",
value
)
})?;
let name = map
.get("name")
.ok_or_else(|| anyhow!("expect field 'name' in attribute definition, got {}", value))?;
let symb = Symbol::try_from(name)?;
ensure!(
!symb.is_reserved(),
"cannot use reserved symbol {}",
symb
);
ensure!(!symb.is_reserved(), "cannot use reserved symbol {}", symb);
let cardinality = map
.get("cardinality")
.ok_or_else(|| anyhow!("expect field 'cardinality' in {}", value))?

@ -1,8 +1,7 @@
use std::cmp::Reverse;
use std::fmt::{Debug, Formatter};
use std::cmp::{Ordering, Reverse};
use std::fmt::{Debug, Display, Formatter};
use anyhow::{bail, Result};
use ordered_float::OrderedFloat;
use rmp_serde::Serializer;
use serde::Serialize;
use serde_derive::{Deserialize, Serialize};
@ -21,9 +20,7 @@ pub(crate) enum DataValue {
#[serde(rename = "b")]
Bool(bool),
#[serde(rename = "i")]
Int(i64),
#[serde(rename = "f")]
Float(OrderedFloat<f64>),
Number(Number),
#[serde(rename = "s")]
String(SmartString<LazyCompact>),
#[serde(rename = "u")]
@ -43,6 +40,83 @@ pub(crate) enum DataValue {
Bottom,
}
impl From<i64> for DataValue {
fn from(v: i64) -> Self {
DataValue::Number(Number::Int(v))
}
}
impl From<f64> for DataValue {
fn from(v: f64) -> Self {
DataValue::Number(Number::Float(v))
}
}
#[derive(Copy, Clone, Deserialize, Serialize)]
pub(crate) enum Number {
#[serde(rename = "i")]
Int(i64),
#[serde(rename = "f")]
Float(f64),
}
impl PartialEq for Number {
fn eq(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl Eq for Number {}
impl Display for Number {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Number::Int(i) => write!(f, "{}", i),
Number::Float(n) => write!(f, "{}", n),
}
}
}
impl Debug for Number {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Number::Int(i) => write!(f, "{}", i),
Number::Float(n) => write!(f, "{}", n),
}
}
}
impl PartialOrd for Number {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Number {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(Number::Int(i), Number::Float(r)) => {
let l = *i as f64;
match l.total_cmp(&r) {
Ordering::Less => Ordering::Less,
Ordering::Equal => Ordering::Less,
Ordering::Greater => Ordering::Greater,
}
}
(Number::Float(l), Number::Int(i)) => {
let r = *i as f64;
match l.total_cmp(&r) {
Ordering::Less => Ordering::Less,
Ordering::Equal => Ordering::Greater,
Ordering::Greater => Ordering::Greater,
}
}
(Number::Int(l), Number::Int(r)) => l.cmp(r),
(Number::Float(l), Number::Float(r)) => l.total_cmp(r),
}
}
}
impl Debug for DataValue {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
@ -52,12 +126,9 @@ impl Debug for DataValue {
DataValue::Bool(b) => {
write!(f, "{}", b)
}
DataValue::Int(i) => {
DataValue::Number(i) => {
write!(f, "{}", i)
}
DataValue::Float(n) => {
write!(f, "{}", n.0)
}
DataValue::String(s) => {
write!(f, "{:?}", s)
}
@ -101,7 +172,7 @@ impl DataValue {
pub(crate) fn get_entity_id(&self) -> Result<EntityId> {
match self {
DataValue::Int(id) => Ok(EntityId(*id as u64)),
DataValue::Number(Number::Int(id)) => Ok(EntityId(*id as u64)),
_ => bail!("type mismatch: expect type EntId, got value {:?}", self),
}
}

@ -633,7 +633,7 @@ impl SessionTx {
if let Some(o) = value_rep.as_object() {
return if attr.val_type.is_ref_type() {
let eid = self.parse_eid_from_map(o, vld)?;
Ok(InputTerm::Const(DataValue::Int(eid.0 as i64)))
Ok(InputTerm::Const(DataValue::from(eid.0 as i64)))
} else {
Ok(InputTerm::Const(self.parse_value_from_map(o, attr)?))
};

@ -36,7 +36,7 @@ impl SessionTx {
val
})
.collect_vec();
key.push(DataValue::Int(idx as i64));
key.push(DataValue::from(idx as i64));
let key = Tuple(key);
let encoded_key = key.encode_as_key_for_epoch(ret.id, 0);
let encoded_val = tuple.encode_as_key_for_epoch(ret.id, 0);

@ -136,7 +136,7 @@ impl TempStore {
vals.push(tuple.0[idx].clone());
}
}
vals.push(DataValue::Int(serial as i64));
vals.push(DataValue::from(serial as i64));
self.db
.put(&Tuple(vals).encode_as_key_for_epoch(self.id, 0), &[])
}

@ -1,6 +1,6 @@
{"_temp_id": "3742", "continent.code": "EU", "continent.desc": "Europe"}
{"_temp_id": "3743", "continent.code": "AF", "continent.desc": "Africa"}
{"_temp_id": "3744", "continent.desc": "North America"}
{"_temp_id": "3744", "continent.code": "NA", "continent.desc": "North America"}
{"_temp_id": "3745", "continent.code": "SA", "continent.desc": "South America"}
{"_temp_id": "3746", "continent.code": "AS", "continent.desc": "Asia"}
{"_temp_id": "3747", "continent.code": "OC", "continent.desc": "Oceania"}

@ -287,5 +287,22 @@ fn air_routes() -> Result<()> {
.unwrap()
);
let n_airports_by_continent_time = Instant::now();
let res = db.run_script(
r#"
airports_by_continent[?c, count(?a)] := [?a airport.iata ?_], [?c geo.contains ?a];
?[?cont, max(?count)] := airports_by_continent[?c, ?count], [?c continent.code ?cont];
?[?cont, max(?count)] := [?_ continent.code ?cont], ?count is 0;
"#,
)?;
dbg!(n_airports_by_continent_time.elapsed());
assert_eq!(
res,
serde_json::Value::from_str(
r#"[["AF",321],["AN",0],["AS",971],["EU",605],["NA",989],["OC",305],["SA",313]]"#
)
.unwrap()
);
Ok(())
}

Loading…
Cancel
Save