Feature - Use rust_decimal (128b) instead of bigdecimal ("arbitrary" precision) (#1991)

This commit is contained in:
Finn Bear 2023-06-09 08:23:30 -07:00 committed by GitHub
parent c490005007
commit c45fd12509
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 408 additions and 215 deletions

191
Cargo.lock generated
View file

@ -625,18 +625,6 @@ dependencies = [
"zeroize",
]
[[package]]
name = "bigdecimal"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa"
dependencies = [
"num-bigint",
"num-integer",
"num-traits",
"serde",
]
[[package]]
name = "bincode"
version = "1.3.3"
@ -790,6 +778,51 @@ dependencies = [
"cmake",
]
[[package]]
name = "borsh"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b"
dependencies = [
"borsh-derive",
"hashbrown",
]
[[package]]
name = "borsh-derive"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7"
dependencies = [
"borsh-derive-internal",
"borsh-schema-derive-internal",
"proc-macro-crate 0.1.5",
"proc-macro2",
"syn 1.0.109",
]
[[package]]
name = "borsh-derive-internal"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "borsh-schema-derive-internal"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "brotli"
version = "3.3.4"
@ -828,6 +861,28 @@ dependencies = [
"serde",
]
[[package]]
name = "bytecheck"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627"
dependencies = [
"bytecheck_derive",
"ptr_meta",
"simdutf8",
]
[[package]]
name = "bytecheck_derive"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "bytemuck"
version = "1.13.1"
@ -1953,6 +2008,9 @@ name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
dependencies = [
"ahash 0.7.6",
]
[[package]]
name = "headers"
@ -3185,6 +3243,15 @@ dependencies = [
"syn 2.0.18",
]
[[package]]
name = "proc-macro-crate"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
dependencies = [
"toml",
]
[[package]]
name = "proc-macro-crate"
version = "1.3.1"
@ -3391,6 +3458,26 @@ version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac"
[[package]]
name = "ptr_meta"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1"
dependencies = [
"ptr_meta_derive",
]
[[package]]
name = "ptr_meta_derive"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "quick-xml"
version = "0.26.0"
@ -3607,6 +3694,15 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bf2521270932c3c7bed1a59151222bd7643c79310f2916f01925e1e16255698"
[[package]]
name = "rend"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "581008d2099240d37fb08d77ad713bcaec2c4d89d50b5b21a8bb1996bbab68ab"
dependencies = [
"bytecheck",
]
[[package]]
name = "reqwest"
version = "0.11.18"
@ -3696,6 +3792,34 @@ dependencies = [
"winapi",
]
[[package]]
name = "rkyv"
version = "0.7.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0200c8230b013893c0b2d6213d6ec64ed2b9be2e0e016682b7224ff82cff5c58"
dependencies = [
"bitvec",
"bytecheck",
"hashbrown",
"ptr_meta",
"rend",
"rkyv_derive",
"seahash",
"tinyvec",
"uuid",
]
[[package]]
name = "rkyv_derive"
version = "0.7.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2e06b915b5c230a17d7a736d1e2e63ee753c256a8614ef3f5147b13a4f5541d"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "rmp"
version = "0.8.11"
@ -3777,7 +3901,7 @@ dependencies = [
"fnv",
"ident_case",
"indexmap",
"proc-macro-crate",
"proc-macro-crate 1.3.1",
"proc-macro-error",
"proc-macro2",
"quote",
@ -3806,6 +3930,24 @@ dependencies = [
"smallvec",
]
[[package]]
name = "rust_decimal"
version = "1.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26bd36b60561ee1fb5ec2817f198b6fd09fa571c897a5e86d1487cfc2b096dfc"
dependencies = [
"arrayvec",
"borsh",
"bytecheck",
"byteorder",
"bytes",
"num-traits",
"rand 0.8.5",
"rkyv",
"serde",
"serde_json",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
@ -3992,6 +4134,12 @@ dependencies = [
"untrusted",
]
[[package]]
name = "seahash"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
[[package]]
name = "security-framework"
version = "2.9.1"
@ -4155,6 +4303,12 @@ dependencies = [
"libc",
]
[[package]]
name = "simdutf8"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
[[package]]
name = "simple_asn1"
version = "0.6.2"
@ -4331,7 +4485,6 @@ dependencies = [
"async-trait",
"base64 0.21.2",
"bcrypt",
"bigdecimal",
"bincode",
"bung",
"chrono",
@ -4367,6 +4520,7 @@ dependencies = [
"roaring",
"rocksdb",
"rquickjs",
"rust_decimal",
"rustls 0.20.8",
"scrypt",
"semver",
@ -4822,6 +4976,15 @@ dependencies = [
"tracing",
]
[[package]]
name = "toml"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [
"serde",
]
[[package]]
name = "toml_datetime"
version = "0.6.2"

View file

@ -58,7 +58,6 @@ async-trait = "0.1.68"
async-recursion = "1.0.4"
base64_lib = { version = "0.21.1", package = "base64" }
bcrypt = "0.14.0"
bigdecimal = { version = "0.3.1", features = ["serde", "string-only"] }
bung = "0.1.0"
bincode = "1.3.3"
channel = { version = "1.8.0", package = "async-channel" }
@ -93,6 +92,7 @@ regex = "1.8.2"
reqwest = { version = "0.11.18", default-features = false, features = ["json", "stream"], optional = true }
roaring = { version = "0.10.1", features = ["serde"] }
rocksdb = { version = "0.21.0", optional = true }
rust_decimal = { version = "1.29.1", features = [ "maths" ] }
rustls = { version = "0.20.8", optional = true }
snap = "1.1.0"
scrypt = "0.11.0"

View file

@ -262,7 +262,7 @@ mod tests {
test(
vec![Value::from(3.14), Value::from(2.72), Value::from(1.61)].into(),
" is not ",
"3.14 is not 2.72 is not 1.61",
"3.14f is not 2.72f is not 1.61f",
);
}
}

View file

@ -326,6 +326,6 @@ mod tests {
let res = div(one, two);
assert!(res.is_ok());
let out = res.unwrap();
assert_eq!("1.25", format!("{}", out));
assert_eq!("1.25f", format!("{}", out));
}
}

View file

@ -1,7 +1,7 @@
use super::classes;
use crate::sql::number::decimal_is_integer;
use crate::sql::number::Number;
use crate::sql::value::Value;
use bigdecimal::ToPrimitive;
use js::Array;
use js::Class;
use js::Ctx;
@ -26,9 +26,9 @@ impl<'js> IntoJs<'js> for &Value {
Value::Strand(v) => js::String::from_str(ctx, v)?.into_js(ctx),
Value::Number(Number::Int(v)) => Ok(js::Value::new_int(ctx, *v as i32)),
Value::Number(Number::Float(v)) => Ok(js::Value::new_float(ctx, *v)),
Value::Number(Number::Decimal(v)) => match v.is_integer() {
true => Ok(js::Value::new_int(ctx, v.to_i32().unwrap_or_default())),
false => Ok(js::Value::new_float(ctx, v.to_f64().unwrap_or_default())),
&Value::Number(Number::Decimal(v)) => match decimal_is_integer(&v) {
true => Ok(js::Value::new_int(ctx, v.try_into().unwrap_or_default())),
false => Ok(js::Value::new_float(ctx, v.try_into().unwrap_or_default())),
},
Value::Datetime(v) => {
let date: js::Function = ctx.globals().get("Date")?;

View file

@ -73,7 +73,7 @@ mod tests {
let res = cast(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("<int> 1.2345", format!("{}", out));
assert_eq!("<int> 1.2345f", format!("{}", out));
assert_eq!(out, Cast(Kind::Int, 1.2345.into()));
}
@ -83,7 +83,7 @@ mod tests {
let res = cast(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("<string> 1.2345", format!("{}", out));
assert_eq!("<string> 1.2345f", format!("{}", out));
assert_eq!(out, Cast(Kind::String, 1.2345.into()));
}
}

View file

@ -552,12 +552,12 @@ mod tests {
#[test]
fn function_single_not() {
let sql = "not(1.2345)";
let sql = "not(10)";
let res = function(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("not(1.2345)", format!("{}", out));
assert_eq!(out, Function::Normal("not".to_owned(), vec![1.2345.into()]));
assert_eq!("not(10)", format!("{}", out));
assert_eq!(out, Function::Normal("not".to_owned(), vec![10.into()]));
}
#[test]

View file

@ -65,11 +65,11 @@ mod tests {
#[test]
fn future_expression() {
let sql = "<future> { 1.2345 + 5.4321 }";
let sql = "<future> { 5 + 10 }";
let res = future(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("<future> { 1.2345 + 5.4321 }", format!("{}", out));
assert_eq!(out, Future(Block::from(Value::from(Expression::parse("1.2345 + 5.4321")))));
assert_eq!("<future> { 5 + 10 }", format!("{}", out));
assert_eq!(out, Future(Block::from(Value::from(Expression::parse("5 + 10")))));
}
}

View file

@ -3,14 +3,13 @@ use crate::sql::ending::number as ending;
use crate::sql::error::Error::Parser;
use crate::sql::error::IResult;
use crate::sql::strand::Strand;
use bigdecimal::num_traits::Pow;
use bigdecimal::BigDecimal;
use bigdecimal::FromPrimitive;
use bigdecimal::ToPrimitive;
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::character::complete::i64;
use nom::combinator::{map, opt};
use nom::number::complete::recognize_float;
use nom::Err::Failure;
use rust_decimal::prelude::*;
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::fmt::{self, Display, Formatter};
@ -27,7 +26,7 @@ pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Number";
pub enum Number {
Int(i64),
Float(f64),
Decimal(BigDecimal),
Decimal(Decimal),
// Add new variants here
}
@ -63,8 +62,8 @@ impl From<f64> for Number {
}
}
impl From<BigDecimal> for Number {
fn from(v: BigDecimal) -> Self {
impl From<Decimal> for Number {
fn from(v: Decimal) -> Self {
Self::Decimal(v)
}
}
@ -97,10 +96,10 @@ impl TryFrom<&str> for Number {
match v.parse::<i64>() {
// Store it as an i64
Ok(v) => Ok(Self::Int(v)),
// It wasn't parsed as a i64 so parse as a decimal
_ => match BigDecimal::from_str(v) {
// Store it as a BigDecimal
Ok(v) => Ok(Self::Decimal(v)),
// It wasn't parsed as a i64 so parse as a float
_ => match f64::from_str(v) {
// Store it as a float
Ok(v) => Ok(Self::Float(v)),
// It wasn't parsed as a number
_ => Err(()),
},
@ -141,17 +140,17 @@ try_into_prim!(
f32 => to_f32, f64 => to_f64
);
impl TryFrom<Number> for BigDecimal {
impl TryFrom<Number> for Decimal {
type Error = Error;
fn try_from(value: Number) -> Result<Self, Self::Error> {
match value {
Number::Int(v) => match BigDecimal::from_i64(v) {
Number::Int(v) => match Decimal::from_i64(v) {
Some(v) => Ok(v),
None => Err(Error::TryFrom(value.to_string(), "BigDecimal")),
None => Err(Error::TryFrom(value.to_string(), "Decimal")),
},
Number::Float(v) => match BigDecimal::from_f64(v) {
Some(v) => Ok(v),
None => Err(Error::TryFrom(value.to_string(), "BigDecimal")),
Number::Float(v) => match Decimal::try_from(v) {
Ok(v) => Ok(v),
_ => Err(Error::TryFrom(value.to_string(), "Decimal")),
},
Number::Decimal(x) => Ok(x),
}
@ -162,8 +161,8 @@ impl Display for Number {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Number::Int(v) => Display::fmt(v, f),
Number::Float(v) => Display::fmt(v, f),
Number::Decimal(v) => Display::fmt(v, f),
Number::Float(v) => write!(f, "{v}f"),
Number::Decimal(v) => write!(f, "{v}dec"),
}
}
}
@ -198,8 +197,8 @@ impl Number {
pub fn is_integer(&self) -> bool {
match self {
Number::Int(_) => true,
Number::Float(_) => false,
Number::Decimal(v) => v.is_integer(),
Number::Float(v) => v.fract() == 0.0,
Number::Decimal(v) => decimal_is_integer(v),
}
}
@ -207,7 +206,7 @@ impl Number {
match self {
Number::Int(v) => v != &0,
Number::Float(v) => v != &0.0,
Number::Decimal(v) => v != &BigDecimal::default(),
Number::Decimal(v) => v != &Decimal::ZERO,
}
}
@ -215,7 +214,7 @@ impl Number {
match self {
Number::Int(v) => v > &0,
Number::Float(v) => v > &0.0,
Number::Decimal(v) => v > &BigDecimal::default(),
Number::Decimal(v) => v > &Decimal::ZERO,
}
}
@ -223,7 +222,7 @@ impl Number {
match self {
Number::Int(v) => v < &0,
Number::Float(v) => v < &0.0,
Number::Decimal(v) => v < &BigDecimal::default(),
Number::Decimal(v) => v < &Decimal::ZERO,
}
}
@ -231,7 +230,7 @@ impl Number {
match self {
Number::Int(v) => v >= &0,
Number::Float(v) => v >= &0.0,
Number::Decimal(v) => v >= &BigDecimal::default(),
Number::Decimal(v) => v >= &Decimal::ZERO,
}
}
@ -239,7 +238,7 @@ impl Number {
match self {
Number::Int(v) => v <= &0,
Number::Float(v) => v <= &0.0,
Number::Decimal(v) => v <= &BigDecimal::default(),
Number::Decimal(v) => v <= &Decimal::ZERO,
}
}
@ -251,7 +250,7 @@ impl Number {
match self {
Number::Int(v) => v as usize,
Number::Float(v) => v as usize,
Number::Decimal(v) => v.to_usize().unwrap_or_default(),
Number::Decimal(v) => v.try_into().unwrap_or_default(),
}
}
@ -259,7 +258,7 @@ impl Number {
match self {
Number::Int(v) => v,
Number::Float(v) => v as i64,
Number::Decimal(v) => v.to_i64().unwrap_or_default(),
Number::Decimal(v) => v.try_into().unwrap_or_default(),
}
}
@ -267,14 +266,14 @@ impl Number {
match self {
Number::Int(v) => v as f64,
Number::Float(v) => v,
Number::Decimal(v) => v.to_f64().unwrap_or_default(),
Number::Decimal(v) => v.try_into().unwrap_or_default(),
}
}
pub fn as_decimal(self) -> BigDecimal {
pub fn as_decimal(self) -> Decimal {
match self {
Number::Int(v) => BigDecimal::from_i64(v).unwrap_or_default(),
Number::Float(v) => BigDecimal::from_f64(v).unwrap_or_default(),
Number::Int(v) => Decimal::from(v),
Number::Float(v) => Decimal::try_from(v).unwrap_or_default(),
Number::Decimal(v) => v,
}
}
@ -303,14 +302,14 @@ impl Number {
match self {
Number::Int(v) => *v as f64,
Number::Float(v) => *v,
Number::Decimal(v) => v.to_f64().unwrap_or_default(),
&Number::Decimal(v) => v.try_into().unwrap_or_default(),
}
}
pub fn to_decimal(&self) -> BigDecimal {
pub fn to_decimal(&self) -> Decimal {
match self {
Number::Int(v) => BigDecimal::from_i64(*v).unwrap_or_default(),
Number::Float(v) => BigDecimal::from_f64(*v).unwrap_or_default(),
Number::Int(v) => Decimal::try_from(*v).unwrap_or_default(),
Number::Float(v) => Decimal::try_from(*v).unwrap_or_default(),
Number::Decimal(v) => v.clone(),
}
}
@ -331,14 +330,7 @@ impl Number {
match self {
Number::Int(v) => v.into(),
Number::Float(v) => v.ceil().into(),
Number::Decimal(v) => {
if v.digits() > 16 {
let v = (v.to_f64().unwrap_or_default() + 0.5).round();
BigDecimal::from_f64(v).unwrap_or_default().into()
} else {
(v + BigDecimal::from_f32(0.5).unwrap()).round(0).into()
}
}
Number::Decimal(v) => v.ceil().into(),
}
}
@ -346,14 +338,7 @@ impl Number {
match self {
Number::Int(v) => v.into(),
Number::Float(v) => v.floor().into(),
Number::Decimal(v) => {
if v.digits() > 16 {
let v = (v.to_f64().unwrap_or_default() - 0.5).round();
BigDecimal::from_f64(v).unwrap_or_default().into()
} else {
(v - BigDecimal::from_f32(0.5).unwrap()).round(0).into()
}
}
Number::Decimal(v) => v.floor().into(),
}
}
@ -361,14 +346,7 @@ impl Number {
match self {
Number::Int(v) => v.into(),
Number::Float(v) => v.round().into(),
Number::Decimal(v) => {
if v.digits() > 16 {
let v = v.to_f64().unwrap_or_default().round();
BigDecimal::from_f64(v).unwrap_or_default().into()
} else {
v.round(0).into()
}
}
Number::Decimal(v) => v.round().into(),
}
}
@ -376,7 +354,7 @@ impl Number {
match self {
Number::Int(v) => format!("{v:.precision$}").try_into().unwrap_or_default(),
Number::Float(v) => format!("{v:.precision$}").try_into().unwrap_or_default(),
Number::Decimal(v) => format!("{v:.precision$}").try_into().unwrap_or_default(),
Number::Decimal(v) => v.round_dp(precision as u32).into(),
}
}
@ -390,16 +368,11 @@ impl Number {
pub fn pow(self, power: Number) -> Number {
match (self, power) {
(Number::Int(v), Number::Int(p)) if p >= 0 && p < u32::MAX as i64 => {
Number::Int(v.pow(p as u32))
}
(Number::Decimal(v), Number::Int(p)) if p >= 0 && p < u32::MAX as i64 => {
let (as_int, scale) = v.as_bigint_and_exponent();
Number::Decimal(BigDecimal::new(as_int.pow(p as u32), scale * p))
}
(Number::Int(v), Number::Int(p)) => Number::Int(v.pow(p as u32)),
(Number::Decimal(v), Number::Int(p)) => v.powi(p).into(),
// TODO: (Number::Decimal(v), Number::Float(p)) => todo!(),
// TODO: (Number::Decimal(v), Number::Decimal(p)) => todo!(),
(v, p) => Number::Float(v.as_float().pow(p.as_float())),
(v, p) => v.as_float().powf(p.as_float()).into(),
}
}
}
@ -434,14 +407,14 @@ impl PartialEq for Number {
(Number::Int(v), Number::Float(w)) => (*v as f64).eq(w),
(Number::Float(v), Number::Int(w)) => v.eq(&(*w as f64)),
// ------------------------------
(Number::Int(v), Number::Decimal(w)) => BigDecimal::from(*v).eq(w),
(Number::Decimal(v), Number::Int(w)) => v.eq(&BigDecimal::from(*w)),
(Number::Int(v), Number::Decimal(w)) => Decimal::from(*v).eq(w),
(Number::Decimal(v), Number::Int(w)) => v.eq(&Decimal::from(*w)),
// ------------------------------
(Number::Float(v), Number::Decimal(w)) => {
BigDecimal::from_f64(*v).unwrap_or_default().eq(w)
Decimal::from_f64(*v).unwrap_or_default().eq(w)
}
(Number::Decimal(v), Number::Float(w)) => {
v.eq(&BigDecimal::from_f64(*w).unwrap_or_default())
v.eq(&Decimal::from_f64(*w).unwrap_or_default())
}
}
}
@ -457,14 +430,14 @@ impl PartialOrd for Number {
(Number::Int(v), Number::Float(w)) => (*v as f64).partial_cmp(w),
(Number::Float(v), Number::Int(w)) => v.partial_cmp(&(*w as f64)),
// ------------------------------
(Number::Int(v), Number::Decimal(w)) => BigDecimal::from(*v).partial_cmp(w),
(Number::Decimal(v), Number::Int(w)) => v.partial_cmp(&BigDecimal::from(*w)),
(Number::Int(v), Number::Decimal(w)) => Decimal::from(*v).partial_cmp(w),
(Number::Decimal(v), Number::Int(w)) => v.partial_cmp(&Decimal::from(*w)),
// ------------------------------
(Number::Float(v), Number::Decimal(w)) => {
BigDecimal::from_f64(*v).unwrap_or_default().partial_cmp(w)
Decimal::from_f64(*v).unwrap_or_default().partial_cmp(w)
}
(Number::Decimal(v), Number::Float(w)) => {
v.partial_cmp(&BigDecimal::from_f64(*w).unwrap_or_default())
v.partial_cmp(&Decimal::from_f64(*w).unwrap_or_default())
}
}
}
@ -636,7 +609,28 @@ impl Sort for Vec<Number> {
}
pub fn number(i: &str) -> IResult<&str, Number> {
alt((int, decimal))(i)
let (i, v) = recognize_float(i)?;
let (i, suffix) = suffix(i)?;
let (i, _) = ending(i)?;
let number = match suffix {
Suffix::None => Number::try_from(v).map_err(|_| Failure(Parser(i)))?,
Suffix::Float => Number::from(f64::from_str(v).map_err(|_| Failure(Parser(i)))?),
Suffix::Decimal => Number::from(Decimal::from_str(v).map_err(|_| Failure(Parser(i)))?),
};
Ok((i, number))
}
#[derive(Debug)]
enum Suffix {
None,
Float,
Decimal,
}
fn suffix(i: &str) -> IResult<&str, Suffix> {
let (i, opt_suffix) =
opt(alt((map(tag("f"), |_| Suffix::Float), map(tag("dec"), |_| Suffix::Decimal))))(i)?;
Ok((i, opt_suffix.unwrap_or(Suffix::None)))
}
pub fn integer(i: &str) -> IResult<&str, i64> {
@ -645,16 +639,9 @@ pub fn integer(i: &str) -> IResult<&str, i64> {
Ok((i, v))
}
fn int(i: &str) -> IResult<&str, Number> {
let (i, v) = i64(i)?;
let (i, _) = ending(i)?;
Ok((i, Number::from(v)))
}
fn decimal(i: &str) -> IResult<&str, Number> {
let (i, v) = recognize_float(i)?;
let (i, _) = ending(i)?;
Ok((i, Number::try_from(v).map_err(|_| Failure(Parser(i)))?))
/// TODO: This slow but temporary (awaiting https://docs.rs/rust_decimal/latest/rust_decimal/ version >1.29.1)
pub(crate) fn decimal_is_integer(decimal: &Decimal) -> bool {
decimal.fract().is_zero()
}
#[cfg(test)]
@ -663,6 +650,18 @@ mod tests {
use super::*;
use std::ops::Div;
#[test]
fn dec_is_integer() {
assert!(decimal_is_integer(&Decimal::MAX));
assert!(decimal_is_integer(&Decimal::MIN));
for n in -10..10 {
assert!(decimal_is_integer(&Decimal::from(n)));
assert!(!decimal_is_integer(&(Decimal::from(n) + Decimal::from_f32(0.1).unwrap())));
}
assert!(!decimal_is_integer(&Decimal::HALF_PI));
}
#[test]
fn number_int() {
let sql = "123";
@ -685,21 +684,21 @@ mod tests {
#[test]
fn number_float() {
let sql = "123.45";
let sql = "123.45f";
let res = number(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("123.45", format!("{}", out));
assert_eq!(sql, format!("{}", out));
assert_eq!(out, Number::Float(123.45));
}
#[test]
fn number_float_neg() {
let sql = "-123.45";
let sql = "-123.45f";
let res = number(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("-123.45", format!("{}", out));
assert_eq!(sql, format!("{}", out));
assert_eq!(out, Number::Float(-123.45));
}
@ -709,7 +708,7 @@ mod tests {
let res = number(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("1234.5", format!("{}", out));
assert_eq!("1234.5f", format!("{}", out));
assert_eq!(out, Number::Float(1234.5));
}
@ -719,7 +718,7 @@ mod tests {
let res = number(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("-1234.5", format!("{}", out));
assert_eq!("-1234.5f", format!("{}", out));
assert_eq!(out, Number::Float(-1234.5));
}
@ -729,7 +728,7 @@ mod tests {
let res = number(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("123.45", format!("{}", out));
assert_eq!("123.45f", format!("{}", out));
assert_eq!(out, Number::Float(123.45));
}
@ -739,28 +738,26 @@ mod tests {
let res = number(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("-123.45", format!("{}", out));
assert_eq!("-123.45f", format!("{}", out));
assert_eq!(out, Number::Float(-123.45));
}
#[test]
fn number_float_keeps_precision() {
let sql = "13.571938471938472";
let sql = "13.571938471938472f";
let res = number(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("13.571938471938472", format!("{}", out));
assert_eq!(out, Number::try_from("13.571938471938472").unwrap());
assert_eq!(sql, format!("{}", out));
}
#[test]
fn number_decimal_keeps_precision() {
let sql = "13.571938471938471938563985639413947693775636";
let sql = "0.0000000000000000000000000321dec";
let res = number(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("13.571938471938471938563985639413947693775636", format!("{}", out));
assert_eq!(out, Number::try_from("13.571938471938471938563985639413947693775636").unwrap());
assert_eq!(sql, format!("{}", out));
}
#[test]

View file

@ -72,7 +72,7 @@ mod tests {
let res = scoring(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("BM25(1.0,0.6,100)", format!("{}", out))
assert_eq!("BM25(1f,0.6f,100)", format!("{}", out))
}
#[test]

View file

@ -1427,7 +1427,7 @@ mod tests {
},
}
);
assert_eq!(idx.to_string(), "DEFINE INDEX my_index ON my_table FIELDS my_col SEARCH my_analyzer BM25(1.2,0.75,1000) HIGHLIGHTS");
assert_eq!(idx.to_string(), "DEFINE INDEX my_index ON my_table FIELDS my_col SEARCH my_analyzer BM25(1.2f,0.75f,1000) HIGHLIGHTS");
}
#[test]

View file

@ -242,7 +242,7 @@ mod tests {
#[test]
fn select_statement_table_thing() {
let sql = "SELECT *, ((1 + 3) / 4), 1.3999 AS tester FROM test, test:thingy";
let sql = "SELECT *, ((1 + 3) / 4), 1.3999f AS tester FROM test, test:thingy";
let res = select(sql);
assert!(res.is_ok());
let out = res.unwrap().1;

View file

@ -1,32 +1,28 @@
use crate::err::Error;
use crate::sql::value::serde::ser;
use bigdecimal::BigDecimal;
use rust_decimal::Decimal;
use serde::ser::Error as _;
use serde::ser::Impossible;
use std::fmt::Display;
pub(super) struct Serializer;
impl ser::Serializer for Serializer {
type Ok = BigDecimal;
type Ok = Decimal;
type Error = Error;
type SerializeSeq = Impossible<BigDecimal, Error>;
type SerializeTuple = Impossible<BigDecimal, Error>;
type SerializeTupleStruct = Impossible<BigDecimal, Error>;
type SerializeTupleVariant = Impossible<BigDecimal, Error>;
type SerializeMap = Impossible<BigDecimal, Error>;
type SerializeStruct = Impossible<BigDecimal, Error>;
type SerializeStructVariant = Impossible<BigDecimal, Error>;
type SerializeSeq = Impossible<Decimal, Error>;
type SerializeTuple = Impossible<Decimal, Error>;
type SerializeTupleStruct = Impossible<Decimal, Error>;
type SerializeTupleVariant = Impossible<Decimal, Error>;
type SerializeMap = Impossible<Decimal, Error>;
type SerializeStruct = Impossible<Decimal, Error>;
type SerializeStructVariant = Impossible<Decimal, Error>;
const EXPECTED: &'static str = "a struct `BigDecimal`";
const EXPECTED: &'static str = "a struct `Decimal`";
#[inline]
fn collect_str<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
where
T: Display,
{
value.to_string().parse::<BigDecimal>().map_err(Error::custom)
fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> {
value.parse::<Decimal>().map_err(Error::custom)
}
}
@ -38,8 +34,8 @@ mod tests {
#[test]
fn from_i32() {
let decimal = BigDecimal::from(25);
let serialized = decimal.serialize(Serializer.wrap()).unwrap();
let decimal = Decimal::from(25);
let serialized = Serialize::serialize(&decimal, Serializer.wrap()).unwrap();
assert_eq!(decimal, serialized);
}
}

View file

@ -1,8 +1,7 @@
use crate::err::Error;
use crate::sql::value::serde::ser;
use crate::sql::Number;
use bigdecimal::BigDecimal;
use bigdecimal::FromPrimitive as _;
use rust_decimal::Decimal;
use serde::ser::Error as _;
use serde::ser::Impossible;
use serde::ser::Serialize;
@ -44,9 +43,10 @@ impl ser::Serializer for Serializer {
}
fn serialize_i128(self, value: i128) -> Result<Self::Ok, Error> {
match BigDecimal::from_i128(value) {
Some(decimal) => Ok(decimal.into()),
None => Err(Error::TryFrom(value.to_string(), "BigDecimal")),
// TODO: Replace with native 128-bit integer support.
match Decimal::try_from(value) {
Ok(decimal) => Ok(decimal.into()),
_ => Err(Error::TryFrom(value.to_string(), "Decimal")),
}
}
@ -71,9 +71,10 @@ impl ser::Serializer for Serializer {
}
fn serialize_u128(self, value: u128) -> Result<Self::Ok, Error> {
match BigDecimal::from_u128(value) {
Some(decimal) => Ok(decimal.into()),
None => Err(Error::TryFrom(value.to_string(), "BigDecimal")),
// TODO: Replace with native 128-bit integer support.
match Decimal::try_from(value) {
Ok(decimal) => Ok(decimal.into()),
_ => Err(Error::TryFrom(value.to_string(), "Decimal")),
}
}
@ -89,7 +90,7 @@ impl ser::Serializer for Serializer {
#[inline]
fn serialize_str(self, value: &str) -> Result<Self::Ok, Error> {
let decimal = value.parse::<BigDecimal>().map_err(Error::custom)?;
let decimal = value.parse::<Decimal>().map_err(Error::custom)?;
Ok(decimal.into())
}

View file

@ -19,9 +19,8 @@ use crate::sql::Param;
use crate::sql::Strand;
use crate::sql::Table;
use crate::sql::Uuid;
use bigdecimal::BigDecimal;
use bigdecimal::FromPrimitive;
use map::SerializeValueMap;
use rust_decimal::Decimal;
use ser::edges::SerializeEdges;
use ser::expression::SerializeExpression;
use ser::function::SerializeFunction;
@ -96,9 +95,10 @@ impl ser::Serializer for Serializer {
}
fn serialize_i128(self, value: i128) -> Result<Self::Ok, Error> {
match BigDecimal::from_i128(value) {
Some(decimal) => Ok(decimal.into()),
None => Err(Error::TryFrom(value.to_string(), "BigDecimal")),
// TODO: Replace with native 128-bit integer support.
match Decimal::try_from(value) {
Ok(decimal) => Ok(decimal.into()),
_ => Err(Error::TryFrom(value.to_string(), "Decimal")),
}
}
@ -123,9 +123,10 @@ impl ser::Serializer for Serializer {
}
fn serialize_u128(self, value: u128) -> Result<Self::Ok, Error> {
match BigDecimal::from_u128(value) {
Some(decimal) => Ok(decimal.into()),
None => Err(Error::TryFrom(value.to_string(), "BigDecimal")),
// TODO: replace with native 128-bit integer support.
match Decimal::try_from(value) {
Ok(decimal) => Ok(decimal.into()),
_ => Err(Error::TryFrom(value.to_string(), "Decimal")),
}
}

View file

@ -25,6 +25,7 @@ use crate::sql::id::Id;
use crate::sql::idiom::{self, Idiom};
use crate::sql::kind::Kind;
use crate::sql::model::{model, Model};
use crate::sql::number::decimal_is_integer;
use crate::sql::number::{number, Number};
use crate::sql::object::{key, object, Object};
use crate::sql::operation::Operation;
@ -38,9 +39,6 @@ use crate::sql::table::{table, Table};
use crate::sql::thing::{thing, Thing};
use crate::sql::uuid::{uuid as unique, Uuid};
use async_recursion::async_recursion;
use bigdecimal::BigDecimal;
use bigdecimal::FromPrimitive;
use bigdecimal::ToPrimitive;
use chrono::{DateTime, Utc};
use derive::Store;
use fuzzy_matcher::skim::SkimMatcherV2;
@ -53,6 +51,7 @@ use nom::combinator::{map, opt};
use nom::multi::separated_list0;
use nom::multi::separated_list1;
use once_cell::sync::Lazy;
use rust_decimal::prelude::*;
use serde::{Deserialize, Serialize};
use serde_json::Value as Json;
use std::cmp::Ordering;
@ -403,8 +402,8 @@ impl From<f64> for Value {
}
}
impl From<BigDecimal> for Value {
fn from(v: BigDecimal) -> Self {
impl From<Decimal> for Value {
fn from(v: Decimal) -> Self {
Value::Number(Number::from(v))
}
}
@ -654,12 +653,12 @@ impl TryFrom<Value> for f64 {
}
}
impl TryFrom<Value> for BigDecimal {
impl TryFrom<Value> for Decimal {
type Error = Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
match value {
Value::Number(x) => x.try_into(),
_ => Err(Error::TryFrom(value.to_string(), "BigDecimal")),
_ => Err(Error::TryFrom(value.to_string(), "Decimal")),
}
}
}
@ -1175,9 +1174,9 @@ impl Value {
// Attempt to convert an float number
Value::Number(Number::Float(v)) if v.fract() == 0.0 => Ok(v as i64),
// Attempt to convert a decimal number
Value::Number(Number::Decimal(ref v)) if v.is_integer() => match v.to_i64() {
Value::Number(Number::Decimal(v)) if decimal_is_integer(&v) => match v.try_into() {
// The Decimal can be represented as an i64
Some(v) => Ok(v),
Ok(v) => Ok(v),
// The Decimal is out of bounds
_ => Err(Error::CoerceTo {
from: self,
@ -1200,9 +1199,9 @@ impl Value {
// Attempt to convert an float number
Value::Number(Number::Float(v)) if v.fract() == 0.0 => Ok(v as u64),
// Attempt to convert a decimal number
Value::Number(Number::Decimal(ref v)) if v.is_integer() => match v.to_u64() {
Value::Number(Number::Decimal(v)) if decimal_is_integer(&v) => match v.try_into() {
// The Decimal can be represented as an u64
Some(v) => Ok(v),
Ok(v) => Ok(v),
// The Decimal is out of bounds
_ => Err(Error::CoerceTo {
from: self,
@ -1225,11 +1224,11 @@ impl Value {
// Attempt to convert an int number
Value::Number(Number::Int(v)) => Ok(v as f64),
// Attempt to convert a decimal number
Value::Number(Number::Decimal(ref v)) => match v.to_f64() {
Value::Number(Number::Decimal(v)) => match v.try_into() {
// The Decimal can be represented as a f64
Some(v) => Ok(v),
Ok(v) => Ok(v),
// Ths Decimal loses precision
None => Err(Error::CoerceTo {
_ => Err(Error::CoerceTo {
from: self,
into: "f64".into(),
}),
@ -1263,7 +1262,7 @@ impl Value {
// Attempt to convert an float number
Value::Number(Number::Float(v)) if v.fract() == 0.0 => Ok(Number::Int(v as i64)),
// Attempt to convert a decimal number
Value::Number(Number::Decimal(ref v)) if v.is_integer() => match v.to_i64() {
Value::Number(Number::Decimal(ref v)) if decimal_is_integer(v) => match v.to_i64() {
// The Decimal can be represented as an Int
Some(v) => Ok(Number::Int(v)),
// The Decimal is out of bounds
@ -1311,7 +1310,7 @@ impl Value {
// Allow any decimal number
Value::Number(v) if v.is_decimal() => Ok(v),
// Attempt to convert an int number
Value::Number(Number::Int(ref v)) => match BigDecimal::from_i64(*v) {
Value::Number(Number::Int(v)) => match Decimal::from_i64(v) {
// The Int can be represented as a Decimal
Some(v) => Ok(Number::Decimal(v)),
// Ths Int does not convert to a Decimal
@ -1321,7 +1320,7 @@ impl Value {
}),
},
// Attempt to convert an float number
Value::Number(Number::Float(ref v)) => match BigDecimal::from_f64(*v) {
Value::Number(Number::Float(v)) => match Decimal::from_f64(v) {
// The Float can be represented as a Decimal
Some(v) => Ok(Number::Decimal(v)),
// Ths Float does not convert to a Decimal
@ -1724,9 +1723,9 @@ impl Value {
// Attempt to convert an float number
Value::Number(Number::Float(v)) if v.fract() == 0.0 => Ok(Number::Int(v as i64)),
// Attempt to convert a decimal number
Value::Number(Number::Decimal(ref v)) if v.is_integer() => match v.to_i64() {
Value::Number(Number::Decimal(v)) if decimal_is_integer(&v) => match v.try_into() {
// The Decimal can be represented as an Int
Some(v) => Ok(Number::Int(v)),
Ok(v) => Ok(Number::Int(v)),
// The Decimal is out of bounds
_ => Err(Error::ConvertTo {
from: self,
@ -1759,11 +1758,11 @@ impl Value {
// Attempt to convert an int number
Value::Number(Number::Int(v)) => Ok(Number::Float(v as f64)),
// Attempt to convert a decimal number
Value::Number(Number::Decimal(ref v)) => match v.to_f64() {
Value::Number(Number::Decimal(v)) => match v.try_into() {
// The Decimal can be represented as a Float
Some(v) => Ok(Number::Float(v)),
// Ths BigDecimal loses precision
None => Err(Error::ConvertTo {
Ok(v) => Ok(Number::Float(v)),
// The Decimal loses precision
_ => Err(Error::ConvertTo {
from: self,
into: "float".into(),
}),
@ -1792,30 +1791,30 @@ impl Value {
// Allow any decimal number
Value::Number(v) if v.is_decimal() => Ok(v),
// Attempt to convert an int number
Value::Number(Number::Int(ref v)) => match BigDecimal::from_i64(*v) {
Value::Number(Number::Int(ref v)) => match Decimal::try_from(*v) {
// The Int can be represented as a Decimal
Some(v) => Ok(Number::Decimal(v)),
Ok(v) => Ok(Number::Decimal(v)),
// Ths Int does not convert to a Decimal
None => Err(Error::ConvertTo {
_ => Err(Error::ConvertTo {
from: self,
into: "decimal".into(),
}),
},
// Attempt to convert an float number
Value::Number(Number::Float(ref v)) => match BigDecimal::from_f64(*v) {
Value::Number(Number::Float(ref v)) => match Decimal::try_from(*v) {
// The Float can be represented as a Decimal
Some(v) => Ok(Number::Decimal(v)),
Ok(v) => Ok(Number::Decimal(v)),
// Ths Float does not convert to a Decimal
None => Err(Error::ConvertTo {
_ => Err(Error::ConvertTo {
from: self,
into: "decimal".into(),
}),
},
// Attempt to convert a string value
Value::Strand(ref v) => match BigDecimal::from_str(v) {
// The string can be represented as a Float
Value::Strand(ref v) => match Decimal::from_str(v) {
// The string can be represented as a Decimal
Ok(v) => Ok(Number::Decimal(v)),
// Ths string is not a float
// Ths string is not a Decimal
_ => Err(Error::ConvertTo {
from: self,
into: "decimal".into(),
@ -2523,6 +2522,15 @@ impl TryAdd for Value {
(Number::Int(v), Number::Int(w)) if v.checked_add(w).is_none() => {
Err(Error::TryAdd(v.to_string(), w.to_string()))
}
(Number::Decimal(v), Number::Decimal(w)) if v.checked_add(w).is_none() => {
Err(Error::TryAdd(v.to_string(), w.to_string()))
}
(Number::Decimal(v), w) if v.checked_add(w.to_decimal()).is_none() => {
Err(Error::TryAdd(v.to_string(), w.to_string()))
}
(v, Number::Decimal(w)) if v.to_decimal().checked_add(w).is_none() => {
Err(Error::TryAdd(v.to_string(), w.to_string()))
}
(v, w) => Ok(Value::Number(v + w)),
},
(Value::Strand(v), Value::Strand(w)) => Ok(Value::Strand(v + w)),
@ -2549,6 +2557,15 @@ impl TrySub for Value {
(Number::Int(v), Number::Int(w)) if v.checked_sub(w).is_none() => {
Err(Error::TrySub(v.to_string(), w.to_string()))
}
(Number::Decimal(v), Number::Decimal(w)) if v.checked_sub(w).is_none() => {
Err(Error::TrySub(v.to_string(), w.to_string()))
}
(Number::Decimal(v), w) if v.checked_sub(w.to_decimal()).is_none() => {
Err(Error::TrySub(v.to_string(), w.to_string()))
}
(v, Number::Decimal(w)) if v.to_decimal().checked_sub(w).is_none() => {
Err(Error::TrySub(v.to_string(), w.to_string()))
}
(v, w) => Ok(Value::Number(v - w)),
},
(Value::Datetime(v), Value::Datetime(w)) => Ok(Value::Duration(v - w)),
@ -2575,6 +2592,15 @@ impl TryMul for Value {
(Number::Int(v), Number::Int(w)) if v.checked_mul(w).is_none() => {
Err(Error::TryMul(v.to_string(), w.to_string()))
}
(Number::Decimal(v), Number::Decimal(w)) if v.checked_mul(w).is_none() => {
Err(Error::TryMul(v.to_string(), w.to_string()))
}
(Number::Decimal(v), w) if v.checked_mul(w.to_decimal()).is_none() => {
Err(Error::TryMul(v.to_string(), w.to_string()))
}
(v, Number::Decimal(w)) if v.to_decimal().checked_mul(w).is_none() => {
Err(Error::TryMul(v.to_string(), w.to_string()))
}
(v, w) => Ok(Value::Number(v * w)),
},
(v, w) => Err(Error::TryMul(v.to_raw_string(), w.to_raw_string())),
@ -2595,6 +2621,10 @@ impl TryDiv for Value {
match (self, other) {
(Value::Number(v), Value::Number(w)) => match (v, w) {
(_, w) if w == Number::Int(0) => Ok(Value::None),
(Number::Decimal(v), Number::Decimal(w)) if v.checked_div(w).is_none() => {
// Divided a large number by a small number, got an overflowing number
Err(Error::TryDiv(v.to_string(), w.to_string()))
}
(v, w) => Ok(Value::Number(v / w)),
},
(v, w) => Err(Error::TryDiv(v.to_raw_string(), w.to_raw_string())),
@ -2619,6 +2649,9 @@ impl TryPow for Value {
{
Err(Error::TryPow(v.to_string(), w.to_string()))
}
(Number::Decimal(v), Number::Int(w)) if v.checked_powi(w).is_none() => {
Err(Error::TryPow(v.to_string(), w.to_string()))
}
(v, w) => Ok(Value::Number(v.pow(w))),
},
(v, w) => Err(Error::TryPow(v.to_raw_string(), w.to_raw_string())),
@ -2857,8 +2890,8 @@ mod tests {
assert_eq!(String::from("0"), Value::from(0).as_string());
assert_eq!(String::from("1"), Value::from(1).as_string());
assert_eq!(String::from("-1"), Value::from(-1).as_string());
assert_eq!(String::from("1.1"), Value::from(1.1).as_string());
assert_eq!(String::from("-1.1"), Value::from(-1.1).as_string());
assert_eq!(String::from("1.1f"), Value::from(1.1).as_string());
assert_eq!(String::from("-1.1f"), Value::from(-1.1).as_string());
assert_eq!(String::from("3"), Value::from("3").as_string());
assert_eq!(String::from("true"), Value::from("true").as_string());
assert_eq!(String::from("false"), Value::from("false").as_string());
@ -2870,7 +2903,7 @@ mod tests {
assert_eq!(64, std::mem::size_of::<Value>());
assert_eq!(104, std::mem::size_of::<Error>());
assert_eq!(104, std::mem::size_of::<Result<Value, Error>>());
assert_eq!(40, std::mem::size_of::<crate::sql::number::Number>());
assert_eq!(24, std::mem::size_of::<crate::sql::number::Number>());
assert_eq!(24, std::mem::size_of::<crate::sql::strand::Strand>());
assert_eq!(16, std::mem::size_of::<crate::sql::duration::Duration>());
assert_eq!(12, std::mem::size_of::<crate::sql::datetime::Datetime>());

View file

@ -988,7 +988,7 @@ async fn define_statement_search_index() -> Result<(), Error> {
events: {},
fields: {},
tables: {},
indexes: { blog_title: 'DEFINE INDEX blog_title ON blog FIELDS title SEARCH english BM25(1.2,0.75,100) HIGHLIGHTS' },
indexes: { blog_title: 'DEFINE INDEX blog_title ON blog FIELDS title SEARCH english BM25(1.2f,0.75f,100) HIGHLIGHTS' },
}",
);
assert_eq!(tmp, val);

View file

@ -3,7 +3,7 @@ use parse::Parse;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
use surrealdb::kvs::Datastore;
use surrealdb::sql::Value;
use surrealdb::sql::{Number, Value};
// --------------------------------------------------
// array
@ -445,7 +445,7 @@ async fn function_string_join_arr() -> Result<(), Error> {
RETURN array::join([], "");
RETURN array::join(["hello", "world"], ", ");
RETURN array::join(["again", "again", "again"], " and ");
RETURN array::join([42, 3.14, 2.72, 1.61], " and ");
RETURN array::join([42, true, "1.61"], " and ");
"#;
let dbs = Datastore::new("memory").await?;
let ses = Session::for_kv().with_ns("test").with_db("test");
@ -465,7 +465,7 @@ async fn function_string_join_arr() -> Result<(), Error> {
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::from("42 and 3.14 and 2.72 and 1.61");
let val = Value::from("42 and true and 1.61");
assert_eq!(tmp, val);
//
Ok(())
@ -4153,11 +4153,13 @@ async fn function_type_decimal() -> Result<(), Error> {
assert_eq!(res.len(), 2);
//
let tmp = res.remove(0).result?;
let val = Value::parse("13.1043784018");
let val = Value::Number(Number::Decimal("13.1043784018".parse().unwrap()));
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse("13.5719384719384719385639856394139476937756394756");
let val = Value::Number(Number::Decimal(
"13.571938471938471938563985639413947693775639".parse().unwrap(),
));
assert_eq!(tmp, val);
//
Ok(())
@ -4293,7 +4295,7 @@ async fn function_type_point() -> Result<(), Error> {
async fn function_type_string() -> Result<(), Error> {
let sql = r#"
RETURN type::string(30s);
RETURN type::string(13.58248);
RETURN type::string(13);
"#;
let dbs = Datastore::new("memory").await?;
let ses = Session::for_kv().with_ns("test").with_db("test");
@ -4305,7 +4307,7 @@ async fn function_type_string() -> Result<(), Error> {
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::from("13.58248");
let val = Value::from("13");
assert_eq!(tmp, val);
//
Ok(())

View file

@ -311,7 +311,7 @@ async fn select_multi_aggregate() -> Result<(), Error> {
},
{
group: 2,
one: 7.6,
one: 7.6000000000000005,
two: 12.7,
}
]",
@ -328,7 +328,7 @@ async fn select_multi_aggregate() -> Result<(), Error> {
},
{
group: 2,
one: 7.6,
one: 7.6000000000000005,
two: 12.7,
}
]",
@ -451,7 +451,7 @@ async fn select_multi_aggregate_composed() -> Result<(), Error> {
{
group: 2,
one: 9,
two: 14,
two: 13,
}
]",
);