Skip to content

Commit

Permalink
Update bigdecimal and add implement Display for Decimal (#320)
Browse files Browse the repository at this point in the history
  • Loading branch information
aljazerzen authored Apr 18, 2024
1 parent eeab4a5 commit 00001fb
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 4 deletions.
2 changes: 1 addition & 1 deletion edgedb-protocol/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ snafu = {version="0.8.0"}
uuid = "1.1.2"
num-bigint = {version="0.4.3", optional=true}
num-traits = {version="0.2.10", optional=true}
bigdecimal = {version="0.3.0", optional=true}
bigdecimal = {version="0.4.0", optional=true}
chrono = {version="0.4.23", optional=true, features=["std"], default-features=false}
edgedb-errors = {path = "../edgedb-errors", version = "0.4.0" }
bitflags = "2.4.0"
Expand Down
61 changes: 58 additions & 3 deletions edgedb-protocol/src/model/bignum.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::fmt::Write;

#[cfg(feature = "num-bigint")]
mod num_bigint_interop;

Expand Down Expand Up @@ -146,9 +148,58 @@ impl Decimal {
}
}

impl std::fmt::Display for Decimal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.negative {
write!(f, "-")?;
}

let mut index = 0;

// integer part
while self.weight - index >= 0 {
if let Some(digit) = self.digits.get(index as usize) {
if index == 0 {
write!(f, "{}", digit)?;
} else {
write!(f, "{:04}", digit)?;
}
index += 1;
} else {
break;
}
}
if index == 0 {
write!(f, "0")?;
}

// dot
write!(f, ".")?;

// decimal part
let mut decimals = self.decimal_digits;
while decimals > 0 {
if let Some(digit) = self.digits.get(index as usize) {
let digit = format!("{digit:04}");
let consumed = u16::min(4, decimals);
f.write_str(&digit[0..consumed as usize])?;
decimals -= consumed;
index += 1;
} else {
break;
}
}
// trailing zeros
for _ in 0..decimals {
f.write_char('0')?;
}
Ok(())
}
}

#[cfg(test)]
#[allow(dead_code)] // used by optional tests
mod test_helpers{
mod test_helpers{
use rand::Rng;

pub fn gen_u64<T: Rng>(rng: &mut T) -> u64 {
Expand All @@ -162,6 +213,10 @@ impl Decimal {
let max = 10_i64.pow(rng.gen_range(0..19));
rng.gen_range(-max..max)
}

pub fn gen_f64<T: Rng>(rng: &mut T) -> f64 {
rng.gen::<f64>()
}
}

#[cfg(test)]
Expand Down Expand Up @@ -238,7 +293,7 @@ mod test {
}

#[test]
fn display() {
fn bigint_display() {
let cases = [
0,
1,
Expand All @@ -255,7 +310,7 @@ mod test {
}

#[test]
fn display_rand() {
fn bigint_display_rand() {
use rand::{Rng, SeedableRng, rngs::StdRng};
let mut rng = StdRng::seed_from_u64(4);
for _ in 0..1000 {
Expand Down
38 changes: 38 additions & 0 deletions edgedb-tokio/tests/func/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,41 @@ async fn parallel_queries() -> anyhow::Result<()> {

Ok(())
}

#[tokio::test]
async fn big_num() -> anyhow::Result<()> {
let client = Client::new(&SERVER.config);
client.ensure_connected().await?;

let res = client
.query_required_single::<Value, _>("select 1234567890123456789012345678900000n", &())
.await
.unwrap();
if let Value::BigInt(res) = res {
assert_eq!(res.to_string(), "1234567890123456789012345678900000");
} else {
panic!();
}

let res = client
.query_required_single::<Value, _>("select 1234567891234567890.12345678900000n", &())
.await
.unwrap();
if let Value::Decimal(res) = res {
assert_eq!(res.to_string(), "1234567891234567890.12345678900000");
} else {
panic!();
}

let res = client
.query_required_single::<Value, _>("select 0.00012n", &())
.await
.unwrap();
if let Value::Decimal(res) = res {
assert_eq!(res.to_string(), "0.00012");
} else {
panic!();
}

Ok(())
}

0 comments on commit 00001fb

Please sign in to comment.