Repository: FalkorDB/falkordb-rs-next-gen
Pull request #53: abs, ceil, e, exp, fix #50
Author: login: barakb
Created: 2025-04-29T08:34:22Z | Merged: 2025-04-30T07:46:42Z



<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Added `rand` function returning a random float between 0 and 1.
  - Introduced new mathematical functions: `abs`, `ceil`, `e`, `exp`, `floor`, `log`, `log10`, `pow`, `round`, and `sign` for use in queries.
  - Added `sqrt` function for square root calculations.

- **Bug Fixes**
  - Improved parsing of function calls with empty argument lists to avoid unnecessary parsing steps.

- **Refactor**
  - Streamlined internal number parsing logic for improved maintainability.
  - Simplified runtime function argument handling by accepting argument lists directly.

- **Tests**
  - Added comprehensive tests for the new mathematical functions, including validation of correct results and error handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Linked issue #50: TCK

- [x] regex functions, fix #50 
- [x] implement parse_binary_expr as procedural macro, handle 1 or more alts, fix #50 
- [x] replace simple unit tests with proptest, fix #50 
- [x] Implement unary +, -, fix #50 
- [x] implement Add trait for Value, fix #50 Make TCK tests pass

Diff:
diff --git a/Cargo.lock b/Cargo.lock
index c2893ea8..817cfcef 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -174,6 +174,18 @@ dependencies = [
  "redis-module-macros",
 ]
 
+[[package]]
+name = "getrandom"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasi",
+]
+
 [[package]]
 name = "gimli"
 version = "0.31.1"
@@ -191,6 +203,7 @@ name = "graph"
 version = "0.1.0"
 dependencies = [
  "falkordb-macro",
+ "rand",
  "regex",
  "roaring",
 ]
@@ -368,6 +381,15 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
 [[package]]
 name = "prettyplease"
 version = "0.2.32"
@@ -402,6 +424,41 @@ dependencies = [
  "proc-macro2",
 ]
 
+[[package]]
+name = "r-efi"
+version = "5.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+
+[[package]]
+name = "rand"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
+dependencies = [
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
+dependencies = [
+ "getrandom",
+]
+
 [[package]]
 name = "redis-module"
 version = "2.1.2"
@@ -622,6 +679,15 @@ version = "0.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
 
+[[package]]
+name = "wasi"
+version = "0.14.2+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
 [[package]]
 name = "which"
 version = "4.4.2"
@@ -706,3 +772,32 @@ name = "windows_x86_64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "wit-bindgen-rt"
+version = "0.39.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
+dependencies = [
+ "bitflags 2.9.0",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.8.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
+dependencies = [
+ "proc-macro2",
+ "quote 1.0.40",
+ "syn 2.0.101",
+]
diff --git a/graph/Cargo.toml b/graph/Cargo.toml
index 09b44184..d37d7b1f 100644
--- a/graph/Cargo.toml
+++ b/graph/Cargo.toml
@@ -14,3 +14,4 @@ categories = ["data-structures", "database"]
 roaring = "0.10.12"
 regex = "1.11.1"
 falkordb-macro = { path = "../falkordb-macro" }
+rand = "0.9.1"
diff --git a/graph/src/cypher.rs b/graph/src/cypher.rs
index 53e42e29..271f3117 100644
--- a/graph/src/cypher.rs
+++ b/graph/src/cypher.rs
@@ -1,6 +1,7 @@
 use crate::ast::{
     Alias, NodePattern, PathPattern, Pattern, QueryExprIR, QueryIR, RelationshipPattern,
 };
+use crate::cypher::Token::{RBrace, RParen};
 use falkordb_macro::parse_binary_expr;
 use std::collections::{BTreeMap, HashSet};
 use std::iter::Peekable;
@@ -63,6 +64,24 @@ struct Lexer<'a> {
     cached_current: (Token, usize),
 }
 
+#[derive(Debug)]
+enum ExpressionListType {
+    OneOrMore,
+    ZeroOrMoreClosedBy(Token),
+}
+
+impl ExpressionListType {
+    fn is_end_token(
+        &self,
+        current_token: Token,
+    ) -> bool {
+        match self {
+            ExpressionListType::OneOrMore => false,
+            ExpressionListType::ZeroOrMoreClosedBy(token) => token == &current_token,
+        }
+    }
+}
+
 impl<'a> Lexer<'a> {
     fn new(str: &'a str) -> Self {
         Self {
@@ -258,15 +277,7 @@ impl<'a> Lexer<'a> {
         }
 
         // Integer part digits
-        while let Some(&c) = chars.peek() {
-            if c.is_ascii_digit() {
-                chars.next();
-                len += 1;
-                has_digits_before_dot = true;
-            } else {
-                break;
-            }
-        }
+        Lexer::consume_digits(&mut chars, &mut len, &mut has_digits_before_dot);
 
         let mut has_dot = false;
         let mut has_digits_after_dot = false;
@@ -276,16 +287,7 @@ impl<'a> Lexer<'a> {
             has_dot = true;
             chars.next();
             len += 1;
-
-            while let Some(&c) = chars.peek() {
-                if c.is_ascii_digit() {
-                    chars.next();
-                    len += 1;
-                    has_digits_after_dot = true;
-                } else {
-                    break;
-                }
-            }
+            Lexer::consume_digits(&mut chars, &mut len, &mut has_digits_after_dot);
         }
 
         // Exponent part
@@ -367,6 +369,22 @@ impl<'a> Lexer<'a> {
         }
     }
 
+    fn consume_digits(
+        chars: &mut Peekable<Chars>,
+        len: &mut usize,
+        consume_chars: &mut bool,
+    ) {
+        while let Some(&c) = chars.peek() {
+            if c.is_ascii_digit() {
+                chars.next();
+                *len += 1;
+                *consume_chars = true;
+            } else {
+                break;
+            }
+        }
+    }
+
     fn lex_integer(
         input: &str,
         start_pos: usize,
@@ -540,13 +558,10 @@ impl<'a> Parser<'a> {
     fn parse_call_clause(&mut self) -> Result<QueryIR, String> {
         let ident = self.parse_dotted_ident()?;
         match_token!(self.lexer, LParen);
-        if self.lexer.current() == Token::RParen {
-            self.lexer.next();
-            return Ok(QueryIR::Call(ident, vec![]));
-        }
-        let exprs = self.parse_exprs()?;
-        match_token!(self.lexer, RParen);
-        Ok(QueryIR::Call(ident, exprs))
+        Ok(QueryIR::Call(
+            ident,
+            self.parse_expression_list(ExpressionListType::ZeroOrMoreClosedBy(RParen))?,
+        ))
     }
 
     fn parse_dotted_ident(&mut self) -> Result<String, String> {
@@ -576,7 +591,9 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_delete_clause(&mut self) -> Result<QueryIR, String> {
-        Ok(QueryIR::Delete(self.parse_exprs()?))
+        Ok(QueryIR::Delete(
+            self.parse_expression_list(ExpressionListType::OneOrMore)?,
+        ))
     }
 
     fn parse_where_clause(&mut self) -> Result<QueryIR, String> {
@@ -679,9 +696,10 @@ impl<'a> Parser<'a> {
                 if self.lexer.current() == Token::LParen {
                     self.lexer.next();
 
-                    let exprs = self.parse_exprs()?;
-                    match_token!(self.lexer, RParen);
-                    return Ok(QueryExprIR::FuncInvocation(namespace_and_function, exprs));
+                    return Ok(QueryExprIR::FuncInvocation(
+                        namespace_and_function,
+                        self.parse_expression_list(ExpressionListType::ZeroOrMoreClosedBy(RParen))?,
+                    ));
                 }
                 self.lexer.set_pos(pos);
                 Ok(QueryExprIR::Ident(ident))
@@ -712,13 +730,9 @@ impl<'a> Parser<'a> {
             }
             Token::LBrace => {
                 self.lexer.next();
-                if self.lexer.current() == Token::RBrace {
-                    self.lexer.next();
-                    return Ok(QueryExprIR::List(vec![]));
-                }
-                let exprs = self.parse_exprs()?;
-                match_token!(self.lexer, RBrace);
-                Ok(QueryExprIR::List(exprs))
+                Ok(QueryExprIR::List(self.parse_expression_list(
+                    ExpressionListType::ZeroOrMoreClosedBy(RBrace),
+                )?))
             }
             Token::LBracket => {
                 let attrs = self.parse_map()?;
@@ -915,15 +929,29 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn parse_exprs(&mut self) -> Result<Vec<QueryExprIR>, String> {
+    fn parse_expression_list(
+        &mut self,
+        expression_list_type: ExpressionListType,
+    ) -> Result<Vec<QueryExprIR>, String> {
         let mut exprs = Vec::new();
-        loop {
+        while !expression_list_type.is_end_token(self.lexer.current()) {
             exprs.push(self.parse_expr()?);
             match self.lexer.current() {
                 Token::Comma => self.lexer.next(),
-                _ => return Ok(exprs),
+                _ => break,
+            }
+        }
+
+        if let ExpressionListType::ZeroOrMoreClosedBy(token) = expression_list_type {
+            if self.lexer.current() == token {
+                self.lexer.next();
+            } else {
+                return Err(self
+                    .lexer
+                    .format_error(&format!("Unexpected token {token:?}")));
             }
         }
+        Ok(exprs)
     }
 
     fn parse_node_pattern(&mut self) -> Result<NodePattern, String> {
diff --git a/graph/src/runtime.rs b/graph/src/runtime.rs
index 675483b6..f32949f6 100644
--- a/graph/src/runtime.rs
+++ b/graph/src/runtime.rs
@@ -1,11 +1,12 @@
 use crate::{
     ast::QueryExprIR, graph::Graph, matrix::Iter, planner::IR, value::Contains, value::Value,
 };
+use rand::Rng;
 use std::cmp::Ordering;
 use std::collections::BTreeMap;
 
-type ReadFn = fn(&Graph, &mut Runtime, Value) -> Result<Value, String>;
-type WriteFn = fn(&mut Graph, &mut Runtime, Value) -> Result<Value, String>;
+type ReadFn = fn(&Graph, &mut Runtime, Vec<Value>) -> Result<Value, String>;
+type WriteFn = fn(&mut Graph, &mut Runtime, Vec<Value>) -> Result<Value, String>;
 
 pub struct Runtime {
     read_functions: BTreeMap<String, ReadFn>,
@@ -56,6 +57,18 @@ impl Runtime {
             "string.replaceRegEx".to_string(),
             Self::string_replace_reg_ex,
         );
+        read_functions.insert("abs".to_string(), Self::abs);
+        read_functions.insert("ceil".to_string(), Self::ceil);
+        read_functions.insert("e".to_string(), Self::e);
+        read_functions.insert("exp".to_string(), Self::exp);
+        read_functions.insert("floor".to_string(), Self::floor);
+        read_functions.insert("log".to_string(), Self::log);
+        read_functions.insert("log10".to_string(), Self::log10);
+        read_functions.insert("pow".to_string(), Self::pow);
+        read_functions.insert("rand".to_string(), Self::rand);
+        read_functions.insert("round".to_string(), Self::round);
+        read_functions.insert("sign".to_string(), Self::sign);
+        read_functions.insert("sqrt".to_string(), Self::sqrt);
 
         // internal functions are not accessible from Cypher
         read_functions.insert("@starts_with".to_string(), Self::internal_starts_with);
@@ -86,35 +99,30 @@ impl Runtime {
     fn create_node(
         g: &mut Graph,
         runtime: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(args) => {
-                let mut iter = args.into_iter();
-                match (iter.next(), iter.next(), iter.next()) {
-                    (Some(Value::List(raw_labels)), Some(Value::Map(attrs)), None) => {
-                        let labels = raw_labels
-                            .into_iter()
-                            .filter_map(|label| {
-                                if let Value::String(label) = label {
-                                    Some(label)
-                                } else {
-                                    None
-                                }
-                            })
-                            .collect::<Vec<_>>();
-                        runtime.nodes_created += 1;
-                        runtime.properties_set += attrs
-                            .values()
-                            .map(|v| match v {
-                                Value::Null => 0,
-                                _ => 1,
-                            })
-                            .sum::<i32>();
-                        Ok(g.create_node(&labels, attrs))
-                    }
-                    _ => Ok(Value::Null),
-                }
+        let mut iter = args.into_iter();
+        match (iter.next(), iter.next(), iter.next()) {
+            (Some(Value::List(raw_labels)), Some(Value::Map(attrs)), None) => {
+                let labels = raw_labels
+                    .into_iter()
+                    .filter_map(|label| {
+                        if let Value::String(label) = label {
+                            Some(label)
+                        } else {
+                            None
+                        }
+                    })
+                    .collect::<Vec<_>>();
+                runtime.nodes_created += 1;
+                runtime.properties_set += attrs
+                    .values()
+                    .map(|v| match v {
+                        Value::Null => 0,
+                        _ => 1,
+                    })
+                    .sum::<i32>();
+                Ok(g.create_node(&labels, attrs))
             }
             _ => Ok(Value::Null),
         }
@@ -124,18 +132,13 @@ impl Runtime {
     fn delete_entity(
         g: &mut Graph,
         runtime: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(nodes) => {
-                for n in nodes {
-                    if let Value::Node(id) = n {
-                        runtime.nodes_deleted += 1;
-                        g.delete_node(id);
-                    }
-                }
+        for n in args {
+            if let Value::Node(id) = n {
+                runtime.nodes_deleted += 1;
+                g.delete_node(id);
             }
-            _ => todo!(),
         }
 
         Ok(Value::Null)
@@ -144,537 +147,479 @@ impl Runtime {
     fn create_relationship(
         g: &mut Graph,
         runtime: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(args) => {
-                let mut iter = args.into_iter();
-                match (
-                    iter.next(),
-                    iter.next(),
-                    iter.next(),
-                    iter.next(),
-                    iter.next(),
-                ) {
-                    (
-                        Some(Value::String(relationship_type)),
-                        Some(Value::Node(from)),
-                        Some(Value::Node(to)),
-                        Some(Value::Map(attrs)),
-                        None,
-                    ) => {
-                        runtime.relationships_created += 1;
-                        runtime.properties_set += attrs
-                            .values()
-                            .map(|v| match v {
-                                Value::Null => 0,
-                                _ => 1,
-                            })
-                            .sum::<i32>();
-                        Ok(g.create_relationship(&relationship_type, from, to, attrs))
-                    }
-                    _ => todo!(),
-                }
+        let mut iter = args.into_iter();
+        match (
+            iter.next(),
+            iter.next(),
+            iter.next(),
+            iter.next(),
+            iter.next(),
+        ) {
+            (
+                Some(Value::String(relationship_type)),
+                Some(Value::Node(from)),
+                Some(Value::Node(to)),
+                Some(Value::Map(attrs)),
+                None,
+            ) => {
+                runtime.relationships_created += 1;
+                runtime.properties_set += attrs
+                    .values()
+                    .map(|v| match v {
+                        Value::Null => 0,
+                        _ => 1,
+                    })
+                    .sum::<i32>();
+                Ok(g.create_relationship(&relationship_type, from, to, attrs))
             }
-            _ => unreachable!(),
+            _ => todo!(),
         }
     }
 
     fn create_node_iter(
         g: &Graph,
         runtime: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(args) => {
-                let mut iter = args.into_iter();
-                match (iter.next(), iter.next()) {
-                    (Some(Value::List(raw_labels)), None) => {
-                        runtime.iters.push(
-                            g.get_nodes(
-                                raw_labels
-                                    .into_iter()
-                                    .filter_map(|label| {
-                                        if let Value::String(label) = label {
-                                            Some(label)
-                                        } else {
-                                            None
-                                        }
-                                    })
-                                    .collect::<Vec<_>>()
-                                    .as_slice(),
-                            )
-                            .unwrap(),
-                        );
-                        Ok(Value::Int(runtime.iters.len() as i64 - 1))
-                    }
-                    _ => todo!(),
-                }
+        let mut iter = args.into_iter();
+        match (iter.next(), iter.next()) {
+            (Some(Value::List(raw_labels)), None) => {
+                runtime.iters.push(
+                    g.get_nodes(
+                        raw_labels
+                            .into_iter()
+                            .filter_map(|label| {
+                                if let Value::String(label) = label {
+                                    Some(label)
+                                } else {
+                                    None
+                                }
+                            })
+                            .collect::<Vec<_>>()
+                            .as_slice(),
+                    )
+                    .unwrap(),
+                );
+                Ok(Value::Int(runtime.iters.len() as i64 - 1))
             }
-            _ => unreachable!(),
+            _ => todo!(),
         }
     }
 
     fn next_node(
         _g: &Graph,
         runtime: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(args) => match args.as_slice() {
-                [Value::Int(iter)] => runtime.iters[*iter as usize]
-                    .next()
-                    .map_or_else(|| Ok(Value::Null), |(n, _)| Ok(Value::Node(n))),
-                _ => todo!(),
-            },
-            _ => unreachable!(),
+        match args.as_slice() {
+            [Value::Int(iter)] => runtime.iters[*iter as usize]
+                .next()
+                .map_or_else(|| Ok(Value::Null), |(n, _)| Ok(Value::Node(n))),
+            _ => todo!(),
         }
     }
 
     fn property(
         g: &Graph,
         _runtime: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::Node(node_id), Value::String(property)] => g
-                    .get_node_property_id(property)
-                    .map_or(Ok(Value::Null), |property_id| {
-                        g.get_node_property(*node_id, property_id)
-                            .map_or(Ok(Value::Null), Ok)
-                    }),
-                [Value::Map(map), Value::String(property)] => {
-                    Ok(map.get(property).unwrap_or(&Value::Null).clone())
-                }
-                _ => Ok(Value::Null),
-            },
-            _ => unreachable!(),
+        match args.as_slice() {
+            [Value::Node(node_id), Value::String(property)] => g
+                .get_node_property_id(property)
+                .map_or(Ok(Value::Null), |property_id| {
+                    g.get_node_property(*node_id, property_id)
+                        .map_or(Ok(Value::Null), Ok)
+                }),
+            [Value::Map(map), Value::String(property)] => {
+                Ok(map.get(property).unwrap_or(&Value::Null).clone())
+            }
+            _ => Ok(Value::Null),
         }
     }
 
     fn labels(
         g: &Graph,
         _runtime: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::Node(node_id)] => Ok(Value::List(
-                    g.get_node_label_ids(*node_id)
-                        .map(|label_id| Value::String(g.get_label_by_id(label_id).to_string()))
-                        .collect(),
-                )),
-                _ => Ok(Value::Null),
-            },
-            _ => unreachable!(),
+        match args.as_slice() {
+            [Value::Node(node_id)] => Ok(Value::List(
+                g.get_node_label_ids(*node_id)
+                    .map(|label_id| Value::String(g.get_label_by_id(label_id).to_string()))
+                    .collect(),
+            )),
+            _ => Ok(Value::Null),
+        }
+    }
+
+    fn args_size_error(
+        args: &[Value],
+        function_name: &str,
+        min: usize,
+        max: usize,
+    ) -> Result<Value, String> {
+        if max < args.len() {
+            Err(format!(
+                "Received {} arguments to function '{}', expected at most {}",
+                args.len(),
+                function_name,
+                max
+            ))
+        } else {
+            Err(format!(
+                "Received {} arguments to function '{}', expected at least {}",
+                args.len(),
+                function_name,
+                min
+            ))
         }
     }
 
     fn value_to_integer(
         _g: &Graph,
         _runtime: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(params) => match params.as_slice() {
-                [Value::String(s)] => s.parse::<i64>().map(Value::Int).or_else(|_| {
-                    s.parse::<f64>()
-                        .map(|f| Value::Int(f as i64))
-                        .or(Ok(Value::Null))
-                }),
-                [Value::Int(i)] => Ok(Value::Int(*i)),
-                [Value::Float(f)] => Ok(Value::Int(*f as i64)),
-                [Value::Null] => Ok(Value::Null),
-                [Value::Bool(b)] => Ok(Value::Int(i64::from(*b))),
-                [arg] => Err(format!(
-                    "Type mismatch: expected String, Boolean, Integer, Float, or Null but was {}",
-                    arg.name()
-                )),
-                args => Err(format!(
-                    "Expected one argument for value_to_integer, instead {}",
-                    args.len()
-                )),
-            },
-            _ => unreachable!(),
+        match args.as_slice() {
+            [Value::String(s)] => s.parse::<i64>().map(Value::Int).or_else(|_| {
+                s.parse::<f64>()
+                    .map(|f| Value::Int(f as i64))
+                    .or(Ok(Value::Null))
+            }),
+            [Value::Int(i)] => Ok(Value::Int(*i)),
+            [Value::Float(f)] => Ok(Value::Int(*f as i64)),
+            [Value::Null] => Ok(Value::Null),
+            [Value::Bool(b)] => Ok(Value::Int(i64::from(*b))),
+            [arg] => Err(format!(
+                "Type mismatch: expected String, Boolean, Integer, Float, or Null but was {}",
+                arg.name()
+            )),
+            args => Err(format!(
+                "Expected one argument for value_to_integer, instead {}",
+                args.len()
+            )),
         }
     }
 
     fn size(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::String(s)] => Ok(Value::Int(s.len() as i64)),
-                [Value::List(v)] => Ok(Value::Int(v.len() as i64)),
-                [Value::Null] => Ok(Value::Null),
-                [arg] => Err(format!(
-                    "Type mismatch: expected List, String, or Null but was {}",
-                    arg.name()
-                )),
-                args => Err(format!(
-                    "Expected one argument for size, instead {}",
-                    args.len()
-                )),
-            },
-            _ => unreachable!(),
+        match args.as_slice() {
+            [Value::String(s)] => Ok(Value::Int(s.len() as i64)),
+            [Value::List(v)] => Ok(Value::Int(v.len() as i64)),
+            [Value::Null] => Ok(Value::Null),
+            [arg] => Err(format!(
+                "Type mismatch: expected List, String, or Null but was {}",
+                arg.name()
+            )),
+            args => Self::args_size_error(args, "size", 1, 1),
         }
     }
 
     fn head(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::List(v)] => {
-                    if v.is_empty() {
-                        Ok(Value::Null)
-                    } else {
-                        Ok(v[0].clone())
-                    }
+        match args.as_slice() {
+            [Value::List(v)] => {
+                if v.is_empty() {
+                    Ok(Value::Null)
+                } else {
+                    Ok(v[0].clone())
                 }
-                [Value::Null] => Ok(Value::Null),
-                [arg] => Err(format!(
-                    "Type mismatch: expected List or Null but was {}",
-                    arg.name()
-                )),
-                args => Err(format!(
-                    "Expected one argument for head, instead {}",
-                    args.len()
-                )),
-            },
-            _ => unreachable!(),
+            }
+            [Value::Null] => Ok(Value::Null),
+            [arg] => Err(format!(
+                "Type mismatch: expected List or Null but was {}",
+                arg.name()
+            )),
+            args => Self::args_size_error(args, "head", 1, 1),
         }
     }
 
     fn last(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::List(v)] => Ok(v.last().unwrap_or(&Value::Null).clone()),
-                [Value::Null] => Ok(Value::Null),
-                [arg] => Err(format!(
-                    "Type mismatch: expected List or Null but was {}",
-                    arg.name()
-                )),
-                args => Err(format!(
-                    "Expected one argument for last, instead {}",
-                    args.len()
-                )),
-            },
-            _ => unreachable!(),
+        match args.as_slice() {
+            [Value::List(v)] => Ok(v.last().unwrap_or(&Value::Null).clone()),
+            [Value::Null] => Ok(Value::Null),
+            [arg] => Err(format!(
+                "Type mismatch: expected List or Null but was {}",
+                arg.name()
+            )),
+            args => Self::args_size_error(args, "last", 1, 1),
         }
     }
 
     fn tail(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::List(v)] => {
-                    if v.is_empty() {
-                        Ok(Value::List(vec![]))
-                    } else {
-                        Ok(Value::List(v[1..].to_vec()))
-                    }
+        match args.as_slice() {
+            [Value::List(v)] => {
+                if v.is_empty() {
+                    Ok(Value::List(vec![]))
+                } else {
+                    Ok(Value::List(v[1..].to_vec()))
                 }
-                [Value::Null] => Ok(Value::Null),
-                [arg] => Err(format!(
-                    "Type mismatch: expected List or Null but was {}",
-                    arg.name()
-                )),
-                args => Err(format!(
-                    "Expected one argument for tail, instead {}",
-                    args.len()
-                )),
-            },
-            _ => unreachable!(),
+            }
+            [Value::Null] => Ok(Value::Null),
+            [arg] => Err(format!(
+                "Type mismatch: expected List or Null but was {}",
+                arg.name()
+            )),
+            args => Self::args_size_error(args, "tail", 1, 1),
         }
     }
 
     fn reverse(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::List(v)] => {
-                    let mut v = v.clone();
-                    v.reverse();
-                    Ok(Value::List(v))
-                }
-                [Value::Null] => Ok(Value::Null),
-                [Value::String(s)] => Ok(Value::String(s.chars().rev().collect())),
-                [arg] => Err(format!(
-                    "Type mismatch: expected List, String or null, but was {}",
-                    arg.name()
-                )),
-                args => Err(format!(
-                    "Expected one argument for reverse, instead {}",
-                    args.len()
-                )),
-            },
-            _ => unreachable!(),
+        match args.as_slice() {
+            [Value::List(v)] => {
+                let mut v = v.clone();
+                v.reverse();
+                Ok(Value::List(v))
+            }
+            [Value::Null] => Ok(Value::Null),
+            [Value::String(s)] => Ok(Value::String(s.chars().rev().collect())),
+            [arg] => Err(format!(
+                "Type mismatch: expected List, String or null, but was {}",
+                arg.name()
+            )),
+            args => Self::args_size_error(args, "reverse", 1, 1),
         }
     }
 
     fn substring(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                // Handle NULL input case
-                [Value::Null, _] | [Value::Null, _, _] => Ok(Value::Null),
-                // Two-argument version: (string, start)
-                [Value::String(s), Value::Int(start)] => {
-                    let start = *start;
-                    if start < 0 {
-                        return Err("start must be a non-negative integer".into());
-                    }
-                    let start = start as usize;
-
-                    Ok(Value::String(s[start..].to_string()))
+        match args.as_slice() {
+            // Handle NULL input case
+            [Value::Null, _] | [Value::Null, _, _] => Ok(Value::Null),
+            // Two-argument version: (string, start)
+            [Value::String(s), Value::Int(start)] => {
+                let start = *start;
+                if start < 0 {
+                    return Err("start must be a non-negative integer".into());
                 }
+                let start = start as usize;
 
-                // Three-argument version: (string, start, length)
-                [Value::String(s), Value::Int(start), Value::Int(length)] => {
-                    let start = *start;
-                    let length = *length;
-                    if length < 0 {
-                        return Err("length must be a non-negative integer".into());
-                    }
-                    if start < 0 {
-                        return Err("start must be a non-negative integer".into());
-                    }
-                    let start = start as usize;
-                    let length = length as usize;
+                Ok(Value::String(s[start..].to_string()))
+            }
 
-                    let end = start.saturating_add(length).min(s.len());
-                    Ok(Value::String(s[start..end].to_string()))
+            // Three-argument version: (string, start, length)
+            [Value::String(s), Value::Int(start), Value::Int(length)] => {
+                let start = *start;
+                let length = *length;
+                if length < 0 {
+                    return Err("length must be a non-negative integer".into());
+                }
+                if start < 0 {
+                    return Err("start must be a non-negative integer".into());
                 }
+                let start = start as usize;
+                let length = length as usize;
 
-                // Type mismatch handling
-                args => Err(format!(
-                    "Type mismatch: expected substring(String, Integer) [+ Integer] but got {:?}",
-                    args.iter().map(Value::name).collect::<Vec<_>>()
-                )),
-            },
-            _ => unreachable!(),
+                let end = start.saturating_add(length).min(s.len());
+                Ok(Value::String(s[start..end].to_string()))
+            }
+
+            [Value::String(_), t] => Err(format!(
+                "Type mismatch: expected Integer Or Null but got {}",
+                t.name()
+            )),
+            [t, Value::Int(_)] => Err(format!(
+                "Type mismatch: expected String Or Null but got {}",
+                t.name()
+            )),
+            [t, Value::Int(_), Value::Int(_)] => Err(format!(
+                "Type mismatch: expected String Or Null but got {}",
+                t.name()
+            )),
+            [Value::String(_), t, Value::Int(_)] | [Value::String(_), Value::Int(_), t] => {
+                Err(format!(
+                    "Type mismatch: expected Integer Or Null but got {}",
+                    t.name()
+                ))
+            }
+
+            // Type mismatch handling
+            args => Self::args_size_error(args, "substring", 2, 3),
         }
     }
 
     fn split(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::String(string), Value::String(delimiter)] => {
-                    if delimiter.is_empty() {
-                        // split string to characters
-                        let parts: Vec<Value> = string
-                            .chars()
-                            .map(|c| Value::String(c.to_string()))
-                            .collect();
-                        Ok(Value::List(parts))
-                    } else {
-                        let parts: Vec<Value> = string
-                            .split(delimiter.as_str())
-                            .map(|s| Value::String(s.to_string()))
-                            .collect();
-                        Ok(Value::List(parts))
-                    }
+        match args.as_slice() {
+            [Value::String(string), Value::String(delimiter)] => {
+                if delimiter.is_empty() {
+                    // split string to characters
+                    let parts: Vec<Value> = string
+                        .chars()
+                        .map(|c| Value::String(c.to_string()))
+                        .collect();
+                    Ok(Value::List(parts))
+                } else {
+                    let parts: Vec<Value> = string
+                        .split(delimiter.as_str())
+                        .map(|s| Value::String(s.to_string()))
+                        .collect();
+                    Ok(Value::List(parts))
                 }
-                [Value::Null, _] | [_, Value::Null] => Ok(Value::Null),
-                [arg1, arg2] => Err(format!(
-                    "Type mismatch: expected 2 String or null arguments, but was {} {}",
-                    arg1.name(),
-                    arg2.name()
-                )),
-                [arg] => Err(format!(
-                    "Type mismatch: expected 2 String or null arguments, but was {}",
-                    arg.name()
-                )),
-                args => Err(format!(
-                    "Expected two arguments for split, instead {}",
-                    args.len()
-                )),
-            },
-            _ => unreachable!(),
+            }
+            [Value::Null, _] | [_, Value::Null] => Ok(Value::Null),
+            [arg1, arg2] => Err(format!(
+                "Type mismatch: expected 2 String or null arguments, but was {} {}",
+                arg1.name(),
+                arg2.name()
+            )),
+            [arg] => Err(format!(
+                "Type mismatch: expected 2 String or null arguments, but was {}",
+                arg.name()
+            )),
+            args => Self::args_size_error(args, "split", 2, 2),
         }
     }
 
     fn string_to_lower(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::String(s)] => Ok(Value::String(s.to_lowercase())),
-                [Value::Null] => Ok(Value::Null),
-                [arg] => Err(format!(
-                    "Type mismatch: expected List, String or null, but was {}",
-                    arg.name()
-                )),
-                args => Err(format!(
-                    "Expected one argument for toLower, instead {}",
-                    args.len()
-                )),
-            },
-            _ => unreachable!(),
+        match args.as_slice() {
+            [Value::String(s)] => Ok(Value::String(s.to_lowercase())),
+            [Value::Null] => Ok(Value::Null),
+            [arg] => Err(format!(
+                "Type mismatch: expected List, String or null, but was {}",
+                arg.name()
+            )),
+            args => Self::args_size_error(args, "toLower", 1, 1),
         }
     }
 
     fn string_to_upper(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::String(s)] => Ok(Value::String(s.to_uppercase())),
-                [Value::Null] => Ok(Value::Null),
-                [arg] => Err(format!(
-                    "Type mismatch: expected List, String or null, but was {}",
-                    arg.name()
-                )),
-                args => Err(format!(
-                    "Expected one argument for toUpper, instead {}",
-                    args.len()
-                )),
-            },
-            _ => unreachable!(),
+        match args.as_slice() {
+            [Value::String(s)] => Ok(Value::String(s.to_uppercase())),
+            [Value::Null] => Ok(Value::Null),
+            [arg] => Err(format!(
+                "Type mismatch: expected List, String or null, but was {}",
+                arg.name()
+            )),
+            args => Self::args_size_error(args, "toUpper", 1, 1),
         }
     }
 
     fn string_replace(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [
-                    Value::String(s),
-                    Value::String(search),
-                    Value::String(replacement),
-                ] => Ok(Value::String(s.replace(search, replacement))),
-                [Value::Null, _, _] | [_, Value::Null, _] | [_, _, Value::Null] => Ok(Value::Null),
-                [arg1, arg2, arg3] => Err(format!(
-                    "Type mismatch: expected (String, String, String) or null, but was: ({}, {}, {})",
-                    arg1.name(),
-                    arg2.name(),
-                    arg3.name()
-                )),
-                args => Err(format!(
-                    "Expected three arguments for replace, instead {}",
-                    args.len()
-                )),
-            },
-            _ => unreachable!(),
+        match args.as_slice() {
+            [
+                Value::String(s),
+                Value::String(search),
+                Value::String(replacement),
+            ] => Ok(Value::String(s.replace(search, replacement))),
+            [Value::Null, _, _] | [_, Value::Null, _] | [_, _, Value::Null] => Ok(Value::Null),
+            [arg1, arg2, arg3] => Err(format!(
+                "Type mismatch: expected (String, String, String) or null, but was: ({}, {}, {})",
+                arg1.name(),
+                arg2.name(),
+                arg3.name()
+            )),
+            args => Self::args_size_error(args, "replace", 3, 3),
         }
     }
 
     fn string_left(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::String(s), Value::Int(n)] => {
-                    if *n < 0 {
-                        Err("length must be a non-negative integer".to_string())
-                    } else {
-                        Ok(Value::String(s.chars().take(*n as usize).collect()))
-                    }
+        match args.as_slice() {
+            [Value::String(s), Value::Int(n)] => {
+                if *n < 0 {
+                    Err("length must be a non-negative integer".to_string())
+                } else {
+                    Ok(Value::String(s.chars().take(*n as usize).collect()))
                 }
-                [Value::Null, _] => Ok(Value::Null),
-                [_, Value::Null] => Err("length must be a non-negative integer".to_string()),
-                [arg1, arg2] => Err(format!(
-                    "Type mismatch: expected (String, Integer) or null, but was: ({}, {})",
-                    arg1.name(),
-                    arg2.name()
-                )),
-                args => Err(format!(
-                    "Expected two arguments for function 'left', instead {}",
-                    args.len()
-                )),
-            },
-            _ => unreachable!(),
+            }
+            [Value::Null, _] => Ok(Value::Null),
+            [_, Value::Null] => Err("length must be a non-negative integer".to_string()),
+            [arg1, arg2] => Err(format!(
+                "Type mismatch: expected (String, Integer) or null, but was: ({}, {})",
+                arg1.name(),
+                arg2.name()
+            )),
+            args => Self::args_size_error(args, "left", 2, 2),
         }
     }
 
     fn string_ltrim(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::String(s)] => Ok(Value::String(s.trim_start().to_string())),
-                [Value::Null] => Ok(Value::Null),
-                [arg] => Err(format!(
-                    "Type mismatch: expected String or null, but was {}",
-                    arg.name()
-                )),
-                args => Err(format!(
-                    "Expected one argument for ltrim, instead {}",
-                    args.len()
-                )),
-            },
-            _ => unreachable!(),
+        match args.as_slice() {
+            [Value::String(s)] => Ok(Value::String(s.trim_start().to_string())),
+            [Value::Null] => Ok(Value::Null),
+            [arg] => Err(format!(
+                "Type mismatch: expected String or null, but was {}",
+                arg.name()
+            )),
+            args => Self::args_size_error(args, "ltrim", 1, 1),
         }
     }
 
     fn string_right(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::String(s), Value::Int(n)] => {
-                    if *n < 0 {
-                        Err("length must be a non-negative integer".to_string())
-                    } else {
-                        let start = s.len().saturating_sub(*n as usize);
-                        Ok(Value::String(s.chars().skip(start).collect()))
-                    }
+        match args.as_slice() {
+            [Value::String(s), Value::Int(n)] => {
+                if *n < 0 {
+                    Err("length must be a non-negative integer".to_string())
+                } else {
+                    let start = s.len().saturating_sub(*n as usize);
+                    Ok(Value::String(s.chars().skip(start).collect()))
                 }
-                [Value::Null, _] => Ok(Value::Null),
-                [_, Value::Null] => Err("length must be a non-negative integer".to_string()),
-                [arg1, arg2] => Err(format!(
-                    "Type mismatch: expected (String, Integer) or null, but was: ({}, {})",
-                    arg1.name(),
-                    arg2.name()
-                )),
-                args => Err(format!(
-                    "Expected two arguments for function 'right', instead {}",
-                    args.len()
-                )),
-            },
-            _ => unreachable!(),
+            }
+            [Value::Null, _] => Ok(Value::Null),
+            [_, Value::Null] => Err("length must be a non-negative integer".to_string()),
+            [arg1, arg2] => Err(format!(
+                "Type mismatch: expected (String, Integer) or null, but was: ({}, {})",
+                arg1.name(),
+                arg2.name()
+            )),
+            args => Self::args_size_error(args, "right", 2, 2),
         }
     }
     fn string_join(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
         fn to_string_vec(vec: &[Value]) -> Result<Vec<String>, String> {
             vec.iter()
@@ -691,106 +636,304 @@ impl Runtime {
                 .collect()
         }
 
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::List(vec), Value::String(s)] => {
-                    let result = to_string_vec(vec);
-                    result.map(|strings| Value::String(strings.join(s)))
-                }
-                [Value::List(vec)] => {
-                    let result = to_string_vec(vec);
-                    result.map(|strings| Value::String(strings.join("")))
-                }
-                [Value::Null, _] => Ok(Value::Null),
-                [arg1, _arg2] => Err(format!(
-                    "Type mismatch: expected List or Null but was {}",
-                    arg1.name()
-                )),
-                args => Err(format!(
-                    "Received {} arguments to function 'string.join', expected at most 2",
-                    args.len()
-                )),
-            },
-            _ => unreachable!(),
+        match args.as_slice() {
+            [Value::List(vec), Value::String(s)] => {
+                let result = to_string_vec(vec);
+                result.map(|strings| Value::String(strings.join(s)))
+            }
+            [Value::List(vec)] => {
+                let result = to_string_vec(vec);
+                result.map(|strings| Value::String(strings.join("")))
+            }
+            [Value::Null, _] => Ok(Value::Null),
+            [arg1, _arg2] => Err(format!(
+                "Type mismatch: expected List or Null but was {}",
+                arg1.name()
+            )),
+            args => Self::args_size_error(args, "string.join", 1, 2),
         }
     }
 
     fn string_match_reg_ex(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::String(text), Value::String(pattern)] => match regex::Regex::new(pattern) {
-                    Ok(re) => {
-                        let mut all_matches = Vec::new();
-                        for caps in re.captures_iter(text) {
-                            for i in 0..caps.len() {
-                                if let Some(m) = caps.get(i) {
-                                    all_matches.push(Value::String(m.as_str().to_string()));
-                                }
+        match args.as_slice() {
+            [Value::String(text), Value::String(pattern)] => match regex::Regex::new(pattern) {
+                Ok(re) => {
+                    let mut all_matches = Vec::new();
+                    for caps in re.captures_iter(text) {
+                        for i in 0..caps.len() {
+                            if let Some(m) = caps.get(i) {
+                                all_matches.push(Value::String(m.as_str().to_string()));
                             }
                         }
-                        Ok(Value::List(all_matches))
                     }
-                    Err(e) => Err(format!("Invalid regex, {e}")),
-                },
-                [Value::Null, _] | [_, Value::Null] => Ok(Value::List(vec![])),
-                [Value::String(_), arg2] => Err(format!(
-                    "Type mismatch: expected String or Null but was {}",
-                    arg2.name(),
-                )),
-                [arg1, _] => Err(format!(
-                    "Type mismatch: expected String or Null but was {}",
-                    arg1.name(),
-                )),
-                args => Err(format!(
-                    "Received {} arguments to function 'string.matchRegEx', expected at least 2",
-                    args.len()
-                )),
+                    Ok(Value::List(all_matches))
+                }
+                Err(e) => Err(format!("Invalid regex, {e}")),
             },
-            _ => unreachable!(),
+            [Value::Null, _] | [_, Value::Null] => Ok(Value::List(vec![])),
+            [Value::String(_), arg2] => Err(format!(
+                "Type mismatch: expected String or Null but was {}",
+                arg2.name(),
+            )),
+            [arg1, _] => Err(format!(
+                "Type mismatch: expected String or Null but was {}",
+                arg1.name(),
+            )),
+            args => Self::args_size_error(args, "string.matchRegEx", 2, 2),
         }
     }
 
     fn string_replace_reg_ex(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [
-                    Value::String(text),
-                    Value::String(pattern),
-                    Value::String(replacement),
-                ] => match regex::Regex::new(pattern) {
-                    Ok(re) => {
-                        let replaced_text = re.replace_all(text, replacement).to_string();
-                        Ok(Value::String(replaced_text))
-                    }
-                    Err(e) => Err(format!("Invalid regex, {e}")),
-                },
-                [Value::Null, _, _] | [_, Value::Null, _] | [_, _, Value::Null] => Ok(Value::Null),
-                [Value::String(_), arg2, Value::String(_)] => Err(format!(
-                    "Type mismatch: expected String or Null but was {}",
-                    arg2.name(),
-                )),
-                [Value::String(_), Value::String(_), arg3] => Err(format!(
-                    "Type mismatch: expected String or Null but was {}",
-                    arg3.name(),
-                )),
-                [arg1, _, _] => Err(format!(
-                    "Type mismatch: expected String or Null but was {}",
-                    arg1.name(),
-                )),
-                args => Err(format!(
-                    "Received {} arguments to function 'string.replaceRegEx', expected at least 3",
-                    args.len()
-                )),
+        match args.as_slice() {
+            [
+                Value::String(text),
+                Value::String(pattern),
+                Value::String(replacement),
+            ] => match regex::Regex::new(pattern) {
+                Ok(re) => {
+                    let replaced_text = re.replace_all(text, replacement).to_string();
+                    Ok(Value::String(replaced_text))
+                }
+                Err(e) => Err(format!("Invalid regex, {e}")),
             },
-            _ => unreachable!(),
+            [Value::Null, _, _] | [_, Value::Null, _] | [_, _, Value::Null] => Ok(Value::Null),
+            [Value::String(_), arg2, Value::String(_)] => Err(format!(
+                "Type mismatch: expected String or Null but was {}",
+                arg2.name(),
+            )),
+            [Value::String(_), Value::String(_), arg3] => Err(format!(
+                "Type mismatch: expected String or Null but was {}",
+                arg3.name(),
+            )),
+            [arg1, _, _] => Err(format!(
+                "Type mismatch: expected String or Null but was {}",
+                arg1.name(),
+            )),
+            args => Self::args_size_error(args, "string.replaceRegEx", 3, 3),
+        }
+    }
+
+    fn abs(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Int(n.abs())),
+            [Value::Float(f)] => Ok(Value::Float(f.abs())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Self::args_size_error(args, "abs", 1, 1),
+        }
+    }
+
+    fn ceil(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Int(*n)),
+            [Value::Float(f)] => Ok(Value::Float(f.ceil())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Self::args_size_error(args, "ceil", 1, 1),
+        }
+    }
+
+    fn e(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [] => Ok(Value::Float(std::f64::consts::E)),
+            args => Self::args_size_error(args, "e", 0, 0),
+        }
+    }
+
+    fn exp(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Float((*n as f64).exp())),
+            [Value::Float(f)] => Ok(Value::Float(f.exp())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Self::args_size_error(args, "exp", 1, 1),
+        }
+    }
+
+    fn floor(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Int(*n)),
+            [Value::Float(f)] => Ok(Value::Float(f.floor())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Self::args_size_error(args, "floor", 1, 1),
+        }
+    }
+
+    fn log(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Float((*n as f64).ln())),
+            [Value::Float(f)] => Ok(Value::Float(f.ln())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Self::args_size_error(args, "log", 1, 1),
+        }
+    }
+
+    fn log10(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Float((*n as f64).log10())),
+            [Value::Float(f)] => Ok(Value::Float(f.log10())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Self::args_size_error(args, "log10", 1, 1),
+        }
+    }
+    fn pow(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(i1), Value::Int(i2)] => Ok(Value::Float((*i1 as f64).powi(*i2 as i32))),
+            [Value::Float(f1), Value::Float(f2)] => Ok(Value::Float(f1.powf(*f2))),
+            [Value::Int(i1), Value::Float(f1)] => Ok(Value::Float((*i1 as f64).powf(*f1))),
+            [Value::Float(f1), Value::Int(i1)] => Ok(Value::Float(f1.powi(*i1 as i32))),
+            [Value::Null, _] | [_, Value::Null] => Ok(Value::Null),
+            [v, Value::Int(_)] | [v, Value::Float(_)] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            [Value::Int(_), v] | [Value::Float(_), v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Self::args_size_error(args, "pow", 2, 2),
+        }
+    }
+
+    fn rand(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [] => {
+                let mut rng = rand::rng();
+                Ok(Value::Float(rng.random_range(0.0..1.0)))
+            }
+            args => Self::args_size_error(args, "rand", 0, 0),
+        }
+    }
+
+    fn round(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Int(*n)),
+            [Value::Float(f)] => Ok(Value::Float(f.round())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Self::args_size_error(args, "round", 1, 1),
+        }
+    }
+
+    fn sign(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Int(n.signum())),
+            [Value::Float(f)] => Ok(if *f == 0.0 {
+                Value::Int(0)
+            } else {
+                Value::Float(f.signum().round())
+            }),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Self::args_size_error(args, "sign", 1, 1),
+        }
+    }
+
+    fn sqrt(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => {
+                if *n < 0 {
+                    Ok(Value::Float(f64::NAN))
+                } else {
+                    Ok(Value::Float((*n as f64).sqrt()))
+                }
+            }
+            [Value::Float(f)] => {
+                if *f > 0f64 {
+                    Ok(Value::Float(f.sqrt()))
+                } else {
+                    Ok(Value::Float(f64::NAN))
+                }
+            }
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Self::args_size_error(args, "sqrt", 1, 1),
         }
     }
 
@@ -801,20 +944,17 @@ impl Runtime {
     fn internal_starts_with(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::String(s), Value::String(prefix)] => Ok(Value::Bool(s.starts_with(prefix))),
-
-                [_, Value::Null] | [Value::Null, _] => Ok(Value::Null),
-                [arg1, arg2] => Err(format!(
-                    "Type mismatch: expected String or Null but was ({}, {})",
-                    arg1.name(),
-                    arg2.name()
-                )),
-                _ => unreachable!(),
-            },
+        match args.as_slice() {
+            [Value::String(s), Value::String(prefix)] => Ok(Value::Bool(s.starts_with(prefix))),
+
+            [_, Value::Null] | [Value::Null, _] => Ok(Value::Null),
+            [arg1, arg2] => Err(format!(
+                "Type mismatch: expected String or Null but was ({}, {})",
+                arg1.name(),
+                arg2.name()
+            )),
             _ => unreachable!(),
         }
     }
@@ -822,19 +962,16 @@ impl Runtime {
     fn internal_ends_with(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::String(s), Value::String(suffix)] => Ok(Value::Bool(s.ends_with(suffix))),
-                [_, Value::Null] | [Value::Null, _] => Ok(Value::Null),
-                [arg1, arg2] => Err(format!(
-                    "Type mismatch: Type mismatch: expected String or Null but was ({}, {})",
-                    arg1.name(),
-                    arg2.name()
-                )),
-                _ => unreachable!(),
-            },
+        match args.as_slice() {
+            [Value::String(s), Value::String(suffix)] => Ok(Value::Bool(s.ends_with(suffix))),
+            [_, Value::Null] | [Value::Null, _] => Ok(Value::Null),
+            [arg1, arg2] => Err(format!(
+                "Type mismatch: Type mismatch: expected String or Null but was ({}, {})",
+                arg1.name(),
+                arg2.name()
+            )),
             _ => unreachable!(),
         }
     }
@@ -842,21 +979,16 @@ impl Runtime {
     fn internal_contains(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::String(s), Value::String(substring)] => {
-                    Ok(Value::Bool(s.contains(substring)))
-                }
-                [_, Value::Null] | [Value::Null, _] => Ok(Value::Null),
-                [arg1, arg2] => Err(format!(
-                    "Type mismatch: expected String or Null but was ({}, {})",
-                    arg1.name(),
-                    arg2.name()
-                )),
-                _ => unreachable!(),
-            },
+        match args.as_slice() {
+            [Value::String(s), Value::String(substring)] => Ok(Value::Bool(s.contains(substring))),
+            [_, Value::Null] | [Value::Null, _] => Ok(Value::Null),
+            [arg1, arg2] => Err(format!(
+                "Type mismatch: expected String or Null but was ({}, {})",
+                arg1.name(),
+                arg2.name()
+            )),
             _ => unreachable!(),
         }
     }
@@ -864,26 +996,23 @@ impl Runtime {
     fn internal_regex_matches(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::String(s), Value::String(pattern)] => {
-                    // Compile the regex pattern
-                    match regex::Regex::new(pattern) {
-                        Ok(re) => Ok(Value::Bool(re.is_match(s))),
-                        Err(e) => Err(format!("Invalid regex pattern: {e}")),
-                    }
+        match args.as_slice() {
+            [Value::String(s), Value::String(pattern)] => {
+                // Compile the regex pattern
+                match regex::Regex::new(pattern) {
+                    Ok(re) => Ok(Value::Bool(re.is_match(s))),
+                    Err(e) => Err(format!("Invalid regex pattern: {e}")),
                 }
-                [Value::Null, _] | [_, Value::Null] => Ok(Value::Null),
-                [arg1, arg2] => Err(format!(
-                    "Type mismatch: expected (String, String) or null, but was: ({}, {})",
-                    arg1.name(),
-                    arg2.name()
-                )),
-                _ => Err("Expected two arguments for regex matching".to_string()),
-            },
-            _ => unreachable!(),
+            }
+            [Value::Null, _] | [_, Value::Null] => Ok(Value::Null),
+            [arg1, arg2] => Err(format!(
+                "Type mismatch: expected (String, String) or null, but was: ({}, {})",
+                arg1.name(),
+                arg2.name()
+            )),
+            _ => Err("Expected two arguments for regex matching".to_string()),
         }
     }
 
@@ -891,7 +1020,7 @@ impl Runtime {
     fn db_labels(
         g: &Graph,
         _runtime: &mut Self,
-        _args: Value,
+        _args: Vec<Value>,
     ) -> Result<Value, String> {
         Ok(Value::List(
             g.get_labels()
@@ -904,7 +1033,7 @@ impl Runtime {
     fn db_types(
         g: &Graph,
         _runtime: &mut Self,
-        _args: Value,
+        _args: Vec<Value>,
     ) -> Result<Value, String> {
         Ok(Value::List(
             g.get_types()
@@ -917,7 +1046,7 @@ impl Runtime {
     fn db_properties(
         g: &Graph,
         _runtime: &mut Self,
-        _args: Value,
+        _args: Vec<Value>,
     ) -> Result<Value, String> {
         Ok(Value::List(
             g.get_properties()
@@ -1170,7 +1299,7 @@ pub fn ro_run(
                 .collect::<Result<Vec<_>, _>>()?;
             #[allow(clippy::option_if_let_else)]
             if let Some(func) = runtime.read_functions.get(name) {
-                func(g, runtime, Value::List(args))
+                func(g, runtime, args)
             } else {
                 Err(format!("Function {name} not found"))
             }
@@ -1465,9 +1594,9 @@ pub fn run(
                 .map(|ir| run(vars, g, runtime, result_fn, ir))
                 .collect::<Result<Vec<_>, _>>()?;
             if let Some(func) = runtime.write_functions.get(name) {
-                func(g, runtime, Value::List(args))
+                func(g, runtime, args)
             } else if let Some(func) = runtime.read_functions.get(name) {
-                func(g, runtime, Value::List(args))
+                func(g, runtime, args)
             } else {
                 Err(format!("Function {name} not found"))
             }
diff --git a/tests/test_e2e.py b/tests/test_e2e.py
index 271a7a27..33a78fe2 100644
--- a/tests/test_e2e.py
+++ b/tests/test_e2e.py
@@ -3,6 +3,7 @@
 import subprocess
 
 import itertools
+import math
 import pytest
 from falkordb import FalkorDB, Node, Edge
 from redis import Redis, ResponseError
@@ -52,7 +53,13 @@ def query(query: str, params=None, write: bool = False):
     else:
         write_res = g.query(query, params)
         read_res = g.ro_query(query, params)
-        assert write_res.result_set == read_res.result_set
+        assert len(write_res.result_set) == len(read_res.result_set)
+        for i in range(len(write_res.result_set)):
+            assert len(write_res.result_set[i]) == len(read_res.result_set[i])
+            for j in range(len(write_res.result_set[i])):
+                assert (write_res.result_set[i][j] == read_res.result_set[i][j]
+                    or (math.isnan(write_res.result_set[i][j])
+                        and math.isnan(read_res.result_set[i][j])))
         return write_res
 
 
@@ -287,7 +294,6 @@ def test_list_range():
     assert res.result_set == [[[1, 2, 3]]]
 
 
-
 def test_list_concat():
     res = query("RETURN [1, 10, 100] + [4, 5] AS foo")
     assert res.result_set == [[[1, 10, 100, 4, 5]]]
@@ -1254,3 +1260,384 @@ def test_list_re_replace():
         assert False, "Expected an error"
     except ResponseError as e:
         assert "Invalid regex," in str(e)
+
+
+def test_abs():
+    res = query("RETURN abs(1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(1.0) AS name")
+    assert res.result_set == [[1.0]]
+
+    res = query("RETURN abs(-1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(0) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN abs(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN abs({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN abs(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'abs', expected at most 1" in str(e)
+
+
+def test_ceil():
+    res = query("RETURN ceil(1.1) AS name")
+    assert res.result_set == [[2]]
+
+    res = query("RETURN ceil(1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN ceil(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN ceil(-1.1) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN ceil({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN ceil(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'ceil', expected at most 1" in str(e)
+
+
+def test_e():
+    res = query("RETURN e() AS name")
+    assert res.result_set == [[2.71828182845905e0]]
+
+    # wrong number of args
+    try:
+        query("RETURN e(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'e', expected at most 0" in str(e)
+
+
+def test_exp():
+    res = query("RETURN exp(1) AS name")
+    assert res.result_set == [[2.71828182845905]]
+
+    res = query("RETURN exp(0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN exp(-1) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(-1.0) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN exp({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN exp(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'exp', expected at most 1" in str(e)
+
+
+def test_floor():
+    res = query("RETURN floor(1.1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(-1.1) AS name")
+    assert res.result_set == [[-2]]
+
+    res = query("RETURN floor(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN floor(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN floor({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN floor(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'floor', expected at most 1" in str(e)
+
+
+def test_log():
+    res = query("RETURN log(1) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN log(1.0) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN log(0) AS name")
+    assert res.result_set == [[float('-inf')]]
+
+    res = query("RETURN log(-1) AS name")
+    assert math.isnan(res.result_set[0][0])
+
+    res = query("RETURN log(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN log({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN log(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'log', expected at most 1" in str(e)
+
+
+def test_log10():
+    res = query("RETURN log10(1) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN log10(1.0) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN log10(0) AS name")
+    assert res.result_set == [[float('-inf')]]
+
+    res = query("RETURN log10(-1) AS name")
+    assert math.isnan(res.result_set[0][0])
+
+    res = query("RETURN log10(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN log10({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN log10(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'log10', expected at most 1" in str(e)
+
+
+def test_pow():
+    res = query("RETURN pow(2, 3) AS name")
+    assert res.result_set == [[8]]
+
+    res = query("RETURN pow(2.0, 3) AS name")
+    assert res.result_set == [[8.0]]
+
+    res = query("RETURN pow(2.0, 3.0) AS name")
+    assert res.result_set == [[8.0]]
+
+    res = query("RETURN pow(2, 3.0) AS name")
+    assert res.result_set == [[8.0]]
+
+    res = query("RETURN pow(2, -3) AS name")
+    assert res.result_set == [[0.125]]
+
+    res = query("RETURN pow(2, 0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN pow(-2, 3) AS name")
+    assert res.result_set == [[-8]]
+
+    res = query("RETURN pow(-2, -3) AS name")
+    assert res.result_set == [[-0.125]]
+
+    res = query("RETURN pow(-2, 0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN pow(null, 3) AS name")
+    assert res.result_set == [[None]]
+
+    res = query("RETURN pow(3, null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN pow({value}, 3) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+        try:
+            query(f"RETURN pow(2, {value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN pow(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'pow', expected at least 2" in str(e)
+
+
+def test_rand():
+    res = query("RETURN rand() AS name", write=True)
+    assert res.result_set[0][0] >= 0.0
+    assert res.result_set[0][0] < 1.0
+
+    # wrong number of args
+    try:
+        query("RETURN rand(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'rand', expected at most 0" in str(e)
+
+
+def test_round():
+    res = query("RETURN round(1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN round(1.1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN round(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN round(-1.1) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN round(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN round(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN round({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN round(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'round', expected at most 1" in str(e)
+
+
+def test_sign():
+    # Test positive numbers
+    res = query("RETURN sign(5) AS result")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN sign(0.1) AS result")
+    assert res.result_set == [[1]]
+
+    # Test zero
+    res = query("RETURN sign(0) AS result")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN sign(0.0) AS result")
+    assert res.result_set == [[0]]
+
+    # Test negative numbers
+    res = query("RETURN sign(-5) AS result")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN sign(-0.1) AS result")
+    assert res.result_set == [[-1]]
+
+    # Test null
+    res = query("RETURN sign(null) AS result")
+    assert res.result_set == [[None]]
+
+    # Type mismatch
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN sign({value}) AS result")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+    # wrong number of args
+    try:
+        query("RETURN sign(1, 2) AS result")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'sign', expected at most 1" in str(e)
+
+
+def test_sqrt():
+    res = query("RETURN sqrt(4) AS result")
+    assert res.result_set == [[2]]
+
+    res = query("RETURN sqrt(4.0) AS result")
+    assert res.result_set == [[2.0]]
+
+    res = query("RETURN sqrt(0) AS result")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN sqrt(-1) AS result")
+    assert math.isnan(res.result_set[0][0])
+
+    res = query("RETURN sqrt(-1.0) AS result")
+    assert math.isnan(res.result_set[0][0])
+
+    res = query("RETURN sqrt(null) AS result")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN sqrt({value}) AS result")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN sqrt(1, 2) AS result")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'sqrt', expected at most 1" in str(e)


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (4)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (4)</summary><blockquote>

`1258-1284`: **Comprehensive test coverage for `abs` function.**

The test verifies positive, negative, and zero inputs, null handling, type checking, and argument count validation, ensuring the function works correctly across all expected use cases.


Consider using `assertRaises` instead of try/except with `assert False` to follow Python best practices:

```diff
-    try:
-        query(f"RETURN abs({value}) AS r")
-        assert False, "Expected an error"
-    except ResponseError as e:
-        assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+    with pytest.raises(ResponseError) as excinfo:
+        query(f"RETURN abs({value}) AS r")
+    assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(excinfo.value)
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1274-1274: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1281-1281: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1286-1315`: **Thorough test cases for `ceil` function.**

The test covers integer and float inputs, including negative numbers, ensuring the ceiling function behaves correctly in all scenarios, with proper null handling and error validation.


Same suggestion as above for using `pytest.raises` instead of try/except with `assert False`.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1305-1305: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1312-1312: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1317-1327`: **Good test for the `e` constant function.**

The test verifies that `e()` returns the expected mathematical constant and raises the appropriate error when called with arguments.


Same suggestion as above for using `pytest.raises` instead of try/except with `assert False`.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1324-1324: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1329-1357`: **Comprehensive test coverage for `exp` function.**

The test verifies various inputs including positive, negative, and zero values, ensuring the exponential function produces correct results in all cases, with thorough error checking.


Same suggestion as above for using `pytest.raises` instead of try/except with `assert False`.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1348-1348: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1355-1355: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 1dd3006e0b55b685afeb2224ef685de610470771 and dde8d578cfaac574ef1fe9d5e6ffd905b628ef43.

</details>

<details>
<summary>📒 Files selected for processing (4)</summary>

* `falkordb-macro/Cargo.toml` (1 hunks)
* `graph/src/cypher.rs` (4 hunks)
* `graph/src/runtime.rs` (2 hunks)
* `tests/test_e2e.py` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (1)</summary>

<details>
<summary>tests/test_e2e.py (3)</summary><blockquote>

<details>
<summary>tests/tck/test_tck.py (1)</summary>

* `query` (10-11)

</details>
<details>
<summary>graph/src/value.rs (1)</summary>

* `name` (92-104)

</details>
<details>
<summary>graph/src/runtime.rs (1)</summary>

* `e` (847-862)

</details>

</blockquote></details>

</details><details>
<summary>🪛 Ruff (0.8.2)</summary>

<details>
<summary>tests/test_e2e.py</summary>

1274-1274: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1281-1281: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1305-1305: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1312-1312: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1324-1324: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1348-1348: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1355-1355: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (8)</summary><blockquote>

<details>
<summary>falkordb-macro/Cargo.toml (1)</summary>

`12-12`: **Good feature optimization for syn dependency.**

Reducing the feature set from "full" to "parsing" will result in smaller compile times and dependency footprint while still providing the necessary functionality for the parsing requirements.

</details>
<details>
<summary>graph/src/cypher.rs (2)</summary>

`359-373`: **Good refactoring with `consume_digits` helper method.**

This helper method eliminates code duplication by extracting repeated digit consumption logic into a reusable function. The implementation properly handles the Peekable iterator, length tracking, and the consumption flag.

---

`687-689`: **Nice optimization for empty function argument lists.**

This early return avoids unnecessary parsing work when a function is called with no arguments, which is particularly helpful for functions like `e()` that don't take any parameters.

</details>
<details>
<summary>graph/src/runtime.rs (5)</summary>

`59-62`: **Good addition of mathematical functions to the runtime environment.**

The implementation adds four useful mathematical functions to the runtime environment, making them available for Cypher queries.

---

`801-822`: **Well-implemented `abs` function with proper type handling.**

The `abs` function correctly handles integers, floats, and null values, and provides appropriate error messages for invalid argument types and counts.

---

`824-845`: **Properly implemented `ceil` function with thorough edge case handling.**

The `ceil` function handles integers (passing through unchanged), floats (ceiling value), and null values correctly, with proper error handling for invalid types and argument counts.

---

`847-862`: **Clean implementation of the `e` constant function.**

The `e` function correctly returns the mathematical constant e as a float with no arguments required, and includes appropriate error handling for incorrect argument counts.

---

`864-885`: **Well-implemented `exp` function with proper type conversions.**

The `exp` function calculates the exponential (e^x) for integer and float inputs, converting integers to floats before calculation to ensure proper results, and includes thorough error handling.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T08:35:47Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (1)</summary><blockquote>

`1274-1274`: **Consider using `raise AssertionError()` instead of `assert False`.**

While functionally correct, using `assert False` can be problematic when Python is run with the `-O` optimization flag, which removes assertions.

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```


Also applies to: 1281-1281, 1305-1305, 1312-1312, 1324-1324, 1348-1348, 1355-1355, 1379-1379, 1386-1386

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1274-1274: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between dde8d578cfaac574ef1fe9d5e6ffd905b628ef43 and ec753ced89e4dee5b6d314cf5703015cc86fee56.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `graph/src/runtime.rs` (2 hunks)
* `tests/test_e2e.py` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* graph/src/runtime.rs

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (1)</summary>

<details>
<summary>tests/test_e2e.py (3)</summary><blockquote>

<details>
<summary>tests/tck/test_tck.py (1)</summary>

* `query` (10-11)

</details>
<details>
<summary>graph/src/value.rs (1)</summary>

* `name` (92-104)

</details>
<details>
<summary>graph/src/runtime.rs (1)</summary>

* `e` (848-863)

</details>

</blockquote></details>

</details><details>
<summary>🪛 Ruff (0.8.2)</summary>

<details>
<summary>tests/test_e2e.py</summary>

1274-1274: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1281-1281: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1305-1305: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1312-1312: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1324-1324: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1348-1348: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1355-1355: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1379-1379: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1386-1386: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (5)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (5)</summary>

`1258-1284`: **Good implementation of comprehensive tests for the `abs` function!**

The test covers essential scenarios including positive, negative, zero values, null handling, type validation, and argument count validation. This follows the established pattern in the codebase.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1274-1274: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1281-1281: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1286-1315`: **Well-structured tests for the `ceil` function.**

The tests appropriately verify ceiling behavior for various numeric inputs including positive/negative values with and without decimal parts, along with proper error handling.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1305-1305: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1312-1312: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1317-1327`: **Clean and concise test for the mathematical constant `e`.**

The test effectively verifies that the function returns the correct value of e and properly rejects attempts to pass arguments.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1324-1324: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1329-1358`: **Thorough testing of the `exp` function.**

The test covers the full range of scenarios including positive/negative integers, zero, floating-point values, null handling, type checking, and argument validation.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1348-1348: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1355-1355: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1360-1388`: **Complete test coverage for the `floor` function.**

The test successfully verifies floor behavior with various numeric inputs and appropriate error conditions, maintaining consistency with the established testing pattern.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1379-1379: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1386-1386: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T08:52:45Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (7)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (7)</summary><blockquote>

`1261-1287`: **Well-structured test for abs() function**

The test covers positive, negative, zero, and null input values, and properly validates error conditions for incorrect types and arguments.


Consider replacing `assert False` with `raise AssertionError()` to ensure errors are caught even when Python optimization (`-O` flag) is enabled:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1277-1277: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1284-1284: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1289-1318`: **Comprehensive ceil() function test**

The test properly verifies ceiling behavior for both positive and negative numbers with and without decimal portions.


Replace `assert False` with `raise AssertionError()` here as well to follow best practices for test assertions.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1308-1308: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1315-1315: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1320-1330`: **Correct implementation of e() function test**

The test verifies the mathematical constant e is returned with the expected precision and checks argument validation.


Same issue with `assert False` as mentioned previously.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1327-1327: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1332-1361`: **Thorough exp() function test**

The test covers various input scenarios including positive, negative, zero, and null values, with accurate expected results.


Same issue with `assert False` as mentioned previously.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1351-1351: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1358-1358: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1363-1392`: **Well-implemented floor() function test**

The test correctly verifies floor behavior for all relevant cases, including the important case of negative numbers with decimals.


Same issue with `assert False` as mentioned previously.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1382-1382: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1389-1389: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1394-1407`: **Good handling of special cases in log() function test**

The test properly checks the special cases for logarithm (log(1)=0, log(0)=-infinity, log(negative)=NaN) using appropriate assertions.

Remove the debugging print statement on line 1405 before finalizing:

```diff
-    v = res.result_set[0][0]
-    print(f"v: {v}")
+    # For negative numbers, log returns NaN
     assert math.isnan(res.result_set[0][0])
```

---

`1408-1423`: **Complete error handling tests for log() function**

The test includes proper validation for null input, type mismatches, and incorrect argument count.


Same issue with `assert False` as mentioned previously.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1414-1414: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1421-1421: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between ec753ced89e4dee5b6d314cf5703015cc86fee56 and d795ce64b9c3f00d7112a1433550d7f020d5073c.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `graph/src/runtime.rs` (2 hunks)
* `tests/test_e2e.py` (3 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* graph/src/runtime.rs

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

<details>
<summary>tests/test_e2e.py</summary>

1277-1277: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1284-1284: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1308-1308: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1315-1315: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1327-1327: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1351-1351: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1358-1358: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1382-1382: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1389-1389: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1414-1414: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1421-1421: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (2)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (2)</summary>

`6-6`: **Appropriate addition of the math module**

The import of the math module is needed for the new mathematical function tests, particularly for checking NaN values with `isnan()`.

---

`56-58`: **Good enhancement to handle NaN equality in test assertions**

This modification correctly handles the case where mathematical operations might return NaN values, which don't satisfy normal equality checks.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T09:21:06Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>🧹 Nitpick comments (5)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (5)</summary><blockquote>

`1261-1287`: **Test cases for abs() are comprehensive, but use of assert False is not recommended.**

The abs() function tests are well-designed, covering positive/negative numbers, zero, null handling, type validation, and argument validation. However, using `assert False` could be problematic with optimized Python (`-O` flag).

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1277-1277: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1284-1284: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1289-1318`: **Good test coverage for ceil() function, but same assertion issue.**

The test cases cover the essential behaviors of the ceil() function, including integer/float values, signs, and edge cases. The same assertion issue exists here as in the previous test.

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1308-1308: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1315-1315: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1320-1330`: **Correct test for mathematical constant e().**

The test correctly verifies that e() returns the expected mathematical constant with the appropriate precision.


```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1327-1327: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1332-1361`: **Good exp() function test coverage.**

The test cases for exp() are thorough, covering essential values like exp(1), exp(0), exp(-1), and handling of null and invalid types.


```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1351-1351: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1358-1358: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1363-1392`: **Comprehensive test cases for floor() function.**

The test cases for floor() properly cover the essential behaviors, including rounding down for positive and negative numbers.


```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1382-1382: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1389-1389: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between d795ce64b9c3f00d7112a1433550d7f020d5073c and f4fc07550bea73b7736ad3c4c9cd34d5ae4909c3.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `graph/src/runtime.rs` (2 hunks)
* `tests/test_e2e.py` (3 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* graph/src/runtime.rs

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

<details>
<summary>tests/test_e2e.py</summary>

1277-1277: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1284-1284: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1308-1308: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1315-1315: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1327-1327: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1351-1351: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1358-1358: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1382-1382: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1389-1389: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1402-1402: Local variable `v` is assigned to but never used

Remove assignment to unused variable `v`

(F841)

---

1411-1411: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1418-1418: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1431-1431: Local variable `v` is assigned to but never used

Remove assignment to unused variable `v`

(F841)

---

1440-1440: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1447-1447: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (2)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (2)</summary>

`6-6`: **Good addition of the math import for NaN handling.**

The math module is properly imported to support the new mathematical functions being tested and to handle NaN comparisons.

---

`56-58`: **Good enhancement to handle NaN equality checks.**

The query assertion logic has been improved to handle NaN values correctly, which is necessary because NaN != NaN in floating-point comparisons. This ensures tests don't fail when mathematical functions return NaN values.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T09:24:32Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 4**

<details>
<summary>🔭 Outside diff range comments (1)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (1)</summary><blockquote>

`1452-1496`: _🛠️ Refactor suggestion_

**Comprehensive tests for pow() function with assertion improvement needed.**

The tests thoroughly verify the pow() function's behavior with various combinations of base and exponent values, including edge cases like negative bases, zero exponents, and null handling.


Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1480-1480: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1486-1486: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1493-1493: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>♻️ Duplicate comments (3)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (3)</summary><blockquote>

`1423-1450`: **Well-designed test cases for log10() with special values, but contains unused variable.**

Similar to the log() test, this test correctly verifies special cases but has an unused variable 'v' on line 1431.

```diff
-    v = res.result_set[0][0]
     assert math.isnan(res.result_set[0][0])
```

And the same assertion issue:
```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1431-1431: Local variable `v` is assigned to but never used

Remove assignment to unused variable `v`

(F841)

---

1440-1440: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1447-1447: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1394-1421`: _🛠️ Refactor suggestion_

**Well-designed test cases for log() with special values, but contains unused variable.**

The test correctly verifies log(1)=0, log(0)=-infinity, and log(-1)=NaN. There's an unused variable 'v' on line 1402.


```diff
-    v = res.result_set[0][0]
     assert math.isnan(res.result_set[0][0])
```

And the same assertion issue:
```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1402-1402: Local variable `v` is assigned to but never used

Remove assignment to unused variable `v`

(F841)

---

1411-1411: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1418-1418: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1332-1361`: _🛠️ Refactor suggestion_

**Comprehensive tests for exp() function with assertion improvement needed.**

The tests thoroughly verify the exp() function's behavior with various inputs and edge cases.


Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1351-1351: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1358-1358: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between f4fc07550bea73b7736ad3c4c9cd34d5ae4909c3 and de48ac41edaf8a381beb5df62e9a514052601136.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `graph/src/runtime.rs` (2 hunks)
* `tests/test_e2e.py` (3 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (1)</summary>

<details>
<summary>graph/src/runtime.rs (1)</summary><blockquote>

<details>
<summary>graph/src/value.rs (1)</summary>

* `name` (92-104)

</details>

</blockquote></details>

</details><details>
<summary>🪛 Ruff (0.8.2)</summary>

<details>
<summary>tests/test_e2e.py</summary>

1277-1277: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1284-1284: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1308-1308: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1315-1315: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1327-1327: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1351-1351: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1358-1358: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1382-1382: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1389-1389: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1402-1402: Local variable `v` is assigned to but never used

Remove assignment to unused variable `v`

(F841)

---

1411-1411: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1418-1418: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1431-1431: Local variable `v` is assigned to but never used

Remove assignment to unused variable `v`

(F841)

---

1440-1440: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1447-1447: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1480-1480: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1486-1486: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1493-1493: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: falkordb-e2e-compatibility
* GitHub Check: check-files

</details>

<details>
<summary>🔇 Additional comments (11)</summary><blockquote>

<details>
<summary>graph/src/runtime.rs (9)</summary>

`59-66`: **LGTM! New mathematical functions properly registered in read_functions map.**

The eight new mathematical functions are correctly registered in the Runtime struct's read_functions map, making them available for invocation from Cypher queries.

---

`805-826`: **LGTM! Well-implemented abs function with proper type handling.**

The abs function correctly:
- Handles integer and float inputs
- Propagates null inputs
- Returns appropriate error messages for invalid types
- Validates argument count

---

`828-849`: **LGTM! Well-implemented ceil function with proper type handling.**

The ceil function correctly:
- Returns the same value for integers
- Calculates ceiling for float inputs
- Propagates null inputs
- Returns appropriate error messages for invalid types
- Validates argument count

---

`851-866`: **LGTM! Well-implemented e function returning the mathematical constant.**

The e function correctly:
- Returns the mathematical constant e (std::f64::consts::E)
- Validates argument count (requires no arguments)

---

`868-889`: **LGTM! Well-implemented exp function with proper type handling.**

The exp function correctly:
- Computes e^x for integer and float inputs
- Propagates null inputs
- Returns appropriate error messages for invalid types
- Validates argument count

---

`891-912`: **LGTM! Well-implemented floor function with proper type handling.**

The floor function correctly:
- Returns the same value for integers
- Calculates floor for float inputs
- Propagates null inputs
- Returns appropriate error messages for invalid types
- Validates argument count

---

`914-935`: **LGTM! Well-implemented log function with proper type handling.**

The log function correctly:
- Computes natural logarithm for integer and float inputs
- Propagates null inputs
- Returns appropriate error messages for invalid types
- Validates argument count

---

`937-958`: **LGTM! Well-implemented log10 function with proper type handling.**

The log10 function correctly:
- Computes base-10 logarithm for integer and float inputs
- Propagates null inputs
- Returns appropriate error messages for invalid types
- Validates argument count

---

`959-986`: **LGTM! Well-implemented pow function with proper type handling.**

The pow function correctly:
- Handles multiple combinations of integer/float for base and exponent
- Propagates null inputs
- Returns appropriate error messages for invalid types
- Validates argument count

</details>
<details>
<summary>tests/test_e2e.py (2)</summary>

`6-6`: **LGTM! Added math module import for NaN checking.**

The math module is appropriately imported to enable NaN value comparisons in tests.

---

`56-58`: **LGTM! Improved query function to handle NaN values in comparisons.**

The query function now correctly handles NaN values in result comparisons, which is essential for testing mathematical functions like log and log10 with invalid inputs (e.g., negative numbers).

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T10:13:15Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>🔭 Outside diff range comments (1)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (1)</summary><blockquote>

`1450-1494`: _🛠️ Refactor suggestion_

**Thorough testing of pow() function with common and edge cases.**

The tests cover various combinations of bases and exponents including positive, negative, and zero values. The null handling is also well-tested.

As with other test functions, replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1478-1478: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1484-1484: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1491-1491: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>♻️ Duplicate comments (6)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (6)</summary><blockquote>

`1261-1287`: **Comprehensive tests for abs() function with assertion improvement needed.**

The tests thoroughly verify the behavior of the `abs()` function with positive, negative, and null values, as well as error handling for invalid types and argument counts.

Replace assertions with proper AssertionError raising to avoid issues with Python optimization (-O flag):

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1277-1277: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1284-1284: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1289-1318`: **Comprehensive tests for ceil() function with assertion improvement needed.**

The tests thoroughly verify the `ceil()` function's behavior with various floating-point values and integer edge cases.

Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1308-1308: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1315-1315: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1320-1330`: **Comprehensive tests for e() function with assertion improvement needed.**

The tests verify the mathematical constant e is returned and validate error handling for incorrect argument counts.

Replace assertion with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1327-1327: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1363-1392`: **Comprehensive tests for floor() function with assertion improvement needed.**

The tests thoroughly verify the floor() function's behavior with various floating-point values and integer edge cases.

Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1382-1382: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1389-1389: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1394-1420`: **Well-designed test cases for log() with special values, but contains unused variable.**

The test correctly verifies log(1)=0, log(0)=-infinity, and log(-1)=NaN. There's an unused variable 'v' on line 1402 that should be removed.

```diff
-    v = res.result_set[0][0]
     assert math.isnan(res.result_set[0][0])
```

Also, the same assertion issue exists:
```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1410-1410: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1417-1417: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1422-1448`: **Well-designed test cases for log10() with special values, but contains unused variable.**

Similar to the log() test, this test correctly verifies special cases but has an unused variable 'v' on line 1431.

```diff
-    v = res.result_set[0][0]
     assert math.isnan(res.result_set[0][0])
```

And the same assertion issue:
```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1438-1438: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1445-1445: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between de48ac41edaf8a381beb5df62e9a514052601136 and 5ca31ceeacdb4ccc4f661684745e4bc6ab597152.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `tests/test_e2e.py` (3 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (1)</summary>

<details>
<summary>tests/test_e2e.py (3)</summary><blockquote>

<details>
<summary>tests/tck/test_tck.py (1)</summary>

* `query` (10-11)

</details>
<details>
<summary>graph/src/value.rs (1)</summary>

* `name` (92-104)

</details>
<details>
<summary>graph/src/runtime.rs (1)</summary>

* `e` (851-866)

</details>

</blockquote></details>

</details><details>
<summary>🪛 Ruff (0.8.2)</summary>

<details>
<summary>tests/test_e2e.py</summary>

1277-1277: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1284-1284: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1308-1308: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1315-1315: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1327-1327: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1351-1351: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1358-1358: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1382-1382: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1389-1389: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1410-1410: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1417-1417: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1438-1438: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1445-1445: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1478-1478: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1484-1484: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1491-1491: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: coverage
* GitHub Check: test

</details>

<details>
<summary>🔇 Additional comments (1)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (1)</summary>

`56-58`: **Well-implemented NaN handling in result comparison.**

The modification to the `query` function correctly adds support for comparing result sets containing NaN values, which is necessary for the new math functions that can return NaN (like `log` and `log10` for negative inputs).

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T10:16:55Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>🔭 Outside diff range comments (1)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (1)</summary><blockquote>

`1509-1538`: _🛠️ Refactor suggestion_

**Comprehensive test suite for round() function with proper edge case handling.**

The test cases verify round() correctly handles positive numbers, integers, negative numbers, and null values.


Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1528-1528: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1535-1535: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>♻️ Duplicate comments (7)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (7)</summary><blockquote>

`1496-1507`: _🛠️ Refactor suggestion_

**Appropriate test for rand() function with range validation.**

The test correctly verifies that rand() returns a value in the range [0.0, 1.0).


Replace assertion with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1504-1504: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1394-1420`: _🛠️ Refactor suggestion_

**Well-designed test cases for log() with special values, but contains unused variable.**

The test correctly verifies log(1)=0, log(0)=-infinity, and log(-1)=NaN. There's an unused variable 'v' on line 1402 that should be removed.


```diff
-    v = res.result_set[0][0]
     assert math.isnan(res.result_set[0][0])
```

Also, replace assertions with proper AssertionError raising:
```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1410-1410: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1417-1417: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1363-1392`: _🛠️ Refactor suggestion_

**Comprehensive test suite for floor() function with edge case handling.**

The test cases verify floor() correctly handles positive numbers, integers, negative numbers, and null values.


Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1382-1382: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1389-1389: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1332-1361`: _🛠️ Refactor suggestion_

**Thorough test suite for exp() function covering key cases.**

The test suite properly verifies that exp(1) returns e, exp(0) returns 1, and handles negative inputs correctly.


Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1351-1351: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1358-1358: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1289-1318`: _🛠️ Refactor suggestion_

**Comprehensive test cases for ceil() function with proper edge case handling.**

The tests verify ceil() correctly handles various floating-point values, integers, negative numbers, and null values.


Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1308-1308: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1315-1315: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1320-1330`: _🛠️ Refactor suggestion_

**Effective test for the mathematical constant e().**

The test correctly verifies the function returns Euler's constant and validates error handling for incorrect argument counts.


Replace assertion with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1327-1327: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1261-1287`: _🛠️ Refactor suggestion_

**Well-structured test cases for the abs() function with proper validation.**

This test suite thoroughly verifies the abs() function behavior with positive, negative, and null values, as well as error handling for invalid types and argument counts.


Replace assertions with proper AssertionError raising to avoid issues with Python optimization (-O flag):

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1277-1277: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1284-1284: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 2842e6e8aac16c7e01303a9aa09fdae4c94c0260 and c2da2703f5d0fc1d1009eebaaa3df4f5cd4cfa6f.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `graph/src/runtime.rs` (3 hunks)
* `tests/test_e2e.py` (3 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (2)</summary>

<details>
<summary>graph/src/runtime.rs (1)</summary><blockquote>

<details>
<summary>graph/src/value.rs (1)</summary>

* `name` (92-104)

</details>

</blockquote></details>
<details>
<summary>tests/test_e2e.py (3)</summary><blockquote>

<details>
<summary>tests/tck/test_tck.py (1)</summary>

* `query` (10-11)

</details>
<details>
<summary>graph/src/value.rs (1)</summary>

* `name` (92-104)

</details>
<details>
<summary>graph/src/runtime.rs (1)</summary>

* `e` (854-869)

</details>

</blockquote></details>

</details><details>
<summary>🪛 Ruff (0.8.2)</summary>

<details>
<summary>tests/test_e2e.py</summary>

1277-1277: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1284-1284: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1308-1308: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1315-1315: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1327-1327: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1351-1351: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1358-1358: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1382-1382: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1389-1389: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1410-1410: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1417-1417: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1438-1438: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1445-1445: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1478-1478: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1484-1484: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1491-1491: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1504-1504: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1528-1528: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1535-1535: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (12)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (1)</summary>

`56-58`: **Good enhancement to handle NaN values in query result comparisons.**

The addition of NaN handling to the query function allows test assertions to pass when dealing with special floating-point values like those returned by log(-1). This is necessary because NaN values don't compare equal to themselves in standard equality checks.

</details>
<details>
<summary>graph/src/runtime.rs (11)</summary>

`60-69`: **Good registration of mathematical functions in read_functions map.**

All ten mathematical functions are properly registered in the read_functions map, making them available for invocation by the query runtime.

---

`808-829`: **Well-implemented abs() function with proper type checking and error handling.**

The implementation correctly handles integers, floats, and null values, and provides clear error messages for invalid input types and argument counts.

---

`831-852`: **Well-implemented ceil() function following consistent error handling patterns.**

The function properly handles integers, floats, and null values with appropriate type checking.

---

`854-869`: **Simple and effective implementation of e() constant.**

The function correctly returns Euler's constant and validates that no arguments are provided.

---

`871-892`: **Well-implemented exp() function with proper type conversion.**

The implementation correctly handles both integer and float inputs by converting integers to floats before applying the exponential function.

---

`894-915`: **Well-implemented floor() function following consistent error handling patterns.**

The function properly handles integers, floats, and null values with appropriate type checking.

---

`917-938`: **Well-implemented log() function with proper type conversion.**

The natural logarithm implementation correctly handles integer and float inputs with appropriate conversion.

---

`940-961`: **Well-implemented log10() function with proper type conversion.**

The base-10 logarithm implementation correctly handles integer and float inputs with appropriate conversion.

---

`962-989`: **Thorough pow() function implementation handling all type combinations.**

The implementation correctly handles all combinations of integer and float inputs for both base and exponent, using the appropriate methods (powi vs powf) for each case.

---

`1011-1032`: **Well-implemented round() function following consistent error handling patterns.**

The function properly handles integers, floats, and null values with appropriate type checking.

---

`991-1009`: <details>
<summary>❓ Verification inconclusive</summary>

**Verify rand() function implementation using thread_rng().**

The implementation correctly generates random numbers in the range [0.0, 1.0), but the random number generator initialization might need verification.


The code uses `rand::rng()` which doesn't appear to be a standard method in the rand crate. Typically, you would use `rand::thread_rng()`. Please verify that this is the correct way to initialize the random number generator in your environment:

---

🏁 Script executed:

```shell
#!/bin/bash
# Verify the rand crate usage

# Check if there's a custom rng() function somewhere in the codebase
rg -A 3 "fn rng\(\)" --type rust

# Or check if there are extension traits that might provide this method
rg -A 3 "trait.*Rng" --type rust
```

Length of output: 69

---



</details>

**Confirm or replace `rand::rng()`**  

I ran a global search for `fn rng()` and found no custom implementation in the codebase. In the standard rand crate you’d normally call `rand::thread_rng()`.  
Please verify that `rand::rng()` is defined and correctly imported; otherwise, switch to using:  
```rust
let mut rng = rand::thread_rng();
```  

• Location to check: `graph/src/runtime.rs` (around lines 991–1009)

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T12:01:14Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>🔭 Outside diff range comments (1)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (1)</summary><blockquote>

`1540-1573`: _🛠️ Refactor suggestion_

**Comprehensive tests for sign() function covering all sign variants.**

The tests verify proper handling of positive, zero, and negative inputs for both integers and floats, as well as null values.

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1570-1570: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>♻️ Duplicate comments (8)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (8)</summary><blockquote>

`1261-1287`: _🛠️ Refactor suggestion_

**Well-implemented tests for abs() function, but assertion style needs improvement.**

The tests thoroughly verify the abs() function's behavior with positive, negative, and null values, as well as error handling for invalid types and argument counts.

However, the assertion technique should be improved to avoid issues with Python optimization:


```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1277-1277: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1284-1284: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1289-1318`: _🛠️ Refactor suggestion_

**Comprehensive tests for ceil() function with the same assertion issue.**

The tests verify ceil() behavior with various floating-point values and edge cases.


```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1308-1308: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1315-1315: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1320-1330`: _🛠️ Refactor suggestion_

**Concise and effective test for the e() mathematical constant.**

The test verifies that e() returns Euler's number and properly validates error handling for incorrect argument counts.


```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1327-1327: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1332-1361`: _🛠️ Refactor suggestion_

**Thorough exp() function tests covering key mathematical properties.**

The test confirms exp(1) equals e, exp(0) equals 1, and handles negative inputs correctly.


```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1351-1351: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1358-1358: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1363-1392`: _🛠️ Refactor suggestion_

**Good tests for floor() function with all important edge cases.**

The tests verify rounding behavior for positive and negative values, including edge cases with whole numbers.


```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1382-1382: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1389-1389: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1394-1420`: _🛠️ Refactor suggestion_

**Well-designed tests for log() with special values, but contains unused variable.**

The test correctly verifies log(1)=0, log(0)=-infinity, and log(-1)=NaN. There's an unused variable 'v' on line 1402 that should be removed.



```diff
-    v = res.result_set[0][0]
     assert math.isnan(res.result_set[0][0])
```

Also:
```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1410-1410: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1417-1417: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1422-1448`: _🛠️ Refactor suggestion_

**Similar issue in log10() tests - unused variable and assertion style.**

The test for log10() correctly verifies special values but also contains an unused variable.



```diff
-    v = res.result_set[0][0]
     assert math.isnan(res.result_set[0][0])
```

And:
```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1438-1438: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1445-1445: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1450-1494`: _🛠️ Refactor suggestion_

**Comprehensive tests for pow() function with good edge case coverage.**

The tests verify behavior with positive/negative bases, positive/negative exponents, zero exponents, and null handling.


```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1478-1478: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1484-1484: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1491-1491: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between c2da2703f5d0fc1d1009eebaaa3df4f5cd4cfa6f and 777d344f82d325987af157cbc4412483598f6804.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `graph/src/runtime.rs` (3 hunks)
* `tests/test_e2e.py` (3 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

<details>
<summary>tests/test_e2e.py</summary>

1277-1277: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1284-1284: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1308-1308: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1315-1315: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1327-1327: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1351-1351: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1358-1358: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1382-1382: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1389-1389: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1410-1410: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1417-1417: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1438-1438: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1445-1445: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1478-1478: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1484-1484: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1491-1491: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1504-1504: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1528-1528: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1535-1535: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1570-1570: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: test
* GitHub Check: coverage

</details>

<details>
<summary>🔇 Additional comments (14)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (1)</summary>

`56-58`: **Good modification to handle NaN comparisons.**

The update to the query function correctly handles the comparison of NaN values by using `math.isnan()`. This is a necessary addition since NaN values do not compare equal to themselves in standard equality tests.

</details>
<details>
<summary>graph/src/runtime.rs (13)</summary>

`4-4`: **Appropriate import of the rand crate.**

The addition of the rand crate is necessary for implementing the random number generation functionality.

---

`60-71`: **Well-organized registration of mathematical functions.**

The functions are properly registered in the read_functions map, making them available for invocation in queries. All standard mathematical functions are covered.

---

`809-830`: **Well-implemented abs() function with proper type checking.**

The implementation handles integers, floats, and nulls correctly, with appropriate error messages for type mismatches and argument count validation.

---

`832-853`: **Well-implemented ceil() function with appropriate edge case handling.**

The function correctly passes through integers unchanged and applies ceiling to floats, with proper null handling and type checking.

---

`855-870`: **Simple and correct implementation of e() constant function.**

The function returns Euler's number and properly validates that it receives no arguments.

---

`872-893`: **Proper implementation of exp() with type conversion.**

The function correctly handles both integer and float inputs by converting integers to floats before computing the exponential.

---

`895-916`: **Clean implementation of floor() function.**

Similar to ceil(), the implementation correctly handles integers, floats, and nulls with appropriate type checking.

---

`918-939`: **Correct implementation of natural logarithm function.**

The log() function properly computes the natural logarithm and handles type validation appropriately.

---

`941-962`: **Well-implemented base-10 logarithm function.**

The log10() function follows the same pattern as log() but computes base-10 logarithm instead.

---

`963-990`: **Comprehensive implementation of power function.**

The pow() function handles all combinations of integer and float arguments correctly, with proper null propagation and type checking.

---

`992-1010`: **Correct implementation of random number generator.**

The rand() function generates a random number in the range [0.0, 1.0) using the rand crate, with proper argument validation.

---

`1012-1033`: **Proper implementation of round() function.**

The function rounds floats to the nearest integer and passes integers through unchanged, with appropriate null handling.

---

`1035-1060`: **Well-implemented sign() function with special case handling.**

The implementation correctly returns the sign of numbers (1, 0, or -1) and has special handling for zero floats to return an integer zero instead of a float.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T12:17:51Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>🔭 Outside diff range comments (1)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (1)</summary><blockquote>

`1575-1601`: _🛠️ Refactor suggestion_

**Well-structured test suite for sqrt() function with proper NaN checking.**

The test correctly verifies perfect squares, zero, negative values (returns NaN), with proper null handling and type validation.

Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1591-1591: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1598-1598: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>♻️ Duplicate comments (12)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (12)</summary><blockquote>

`1261-1287`: _🛠️ Refactor suggestion_

**Well-written test cases for abs() function, but assertion style should be improved.**

The test covers positive, negative, and null values comprehensively, with proper type validation and argument count checking.

Replace assertions with proper AssertionError raising to avoid issues with Python optimization (-O flag):

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1277-1277: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1284-1284: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1289-1318`: _🛠️ Refactor suggestion_

**Well-structured tests for ceil() function with same assertion issue.**

The tests properly verify the ceiling function for various floating-point values, integers, and edge cases.

Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1308-1308: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1315-1315: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1320-1330`: _🛠️ Refactor suggestion_

**Good test for mathematical constant e() with same assertion issue.**

The test verifies the correct mathematical constant is returned and properly validates argument counts.

Replace assertion with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1327-1327: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1332-1361`: _🛠️ Refactor suggestion_

**Comprehensive tests for exp() function with same assertion issue.**

The tests verify key properties like exp(1) = e, exp(0) = 1, and handle negative inputs correctly.

Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1351-1351: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1358-1358: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1363-1392`: _🛠️ Refactor suggestion_

**Well-designed test cases for floor() function with same assertion issue.**

The tests thoroughly verify the floor() function's behavior with various floating-point values and integer edge cases.

Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1382-1382: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1389-1389: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1394-1403`: _🛠️ Refactor suggestion_

**Well-designed test cases for log() with special values, but contains unused variable.**

The test correctly verifies log(1)=0, log(0)=-infinity, and log(-1)=NaN. However, there's an unused variable 'v' on line 1402 that should be removed.

```diff
-    v = res.result_set[0][0]
     assert math.isnan(res.result_set[0][0])
```

---

`1404-1420`: _🛠️ Refactor suggestion_

**Comprehensive error handling tests for log() with same assertion issue.**

Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1410-1410: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1417-1417: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1422-1431`: _🛠️ Refactor suggestion_

**Well-designed test cases for log10() with special values, but contains unused variable.**

Similar to the log() test, this test correctly verifies special cases but has an unused variable 'v' on line 1431 that should be removed.

```diff
-    v = res.result_set[0][0]
     assert math.isnan(res.result_set[0][0])
```

---

`1432-1448`: _🛠️ Refactor suggestion_

**Comprehensive error handling tests for log10() with same assertion issue.**

Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1438-1438: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1445-1445: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1450-1494`: _🛠️ Refactor suggestion_

**Comprehensive test suite for pow() function covering various edge cases.**

The test verifies positive/negative bases, positive/negative exponents, zero exponents, and null handling.

Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1478-1478: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1484-1484: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1491-1491: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1496-1507`: _🛠️ Refactor suggestion_

**Good basic test for rand() function checking output range.**

The test verifies that rand() returns a value in the range [0.0, 1.0), which is the expected behavior for a random number generator.

Replace assertion with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1504-1504: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

---

`1509-1538`: _🛠️ Refactor suggestion_

**Thorough round() function tests covering all rounding scenarios.**

The tests verify rounding behavior for positive and negative values, handling of integers, and null inputs.

Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1528-1528: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1535-1535: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 777d344f82d325987af157cbc4412483598f6804 and 12cf33433719ba9cefbfbae2405cfeca7c807f8f.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `graph/src/runtime.rs` (3 hunks)
* `tests/test_e2e.py` (3 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

<details>
<summary>tests/test_e2e.py</summary>

1277-1277: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1284-1284: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1308-1308: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1315-1315: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1327-1327: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1351-1351: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1358-1358: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1382-1382: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1389-1389: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1410-1410: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1417-1417: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1438-1438: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1445-1445: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1478-1478: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1484-1484: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1491-1491: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1504-1504: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1528-1528: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1535-1535: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1570-1570: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1591-1591: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1598-1598: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: coverage
* GitHub Check: test

</details>

<details>
<summary>🔇 Additional comments (15)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (1)</summary>

`56-58`: **Good addition to handle NaN values in query comparison.**

The modification to the `query` function correctly handles NaN values by using `math.isnan()`, which is necessary because NaN values don't compare equal to themselves in normal equality comparisons.

</details>
<details>
<summary>graph/src/runtime.rs (14)</summary>

`4-4`: **Appropriate import of the rand crate for the new random number function.**

Adding the rand crate is necessary for implementing the rand() function.

---

`60-71`: **Well-organized registration of new mathematical functions.**

All twelve mathematical functions are properly registered in the read_functions map with appropriate names.

---

`810-831`: **Correct implementation of abs() function with proper error handling.**

The implementation properly handles integers, floats, and null values, with appropriate type checking and error messages.

---

`833-854`: **Correct implementation of ceil() function with proper error handling.**

The implementation properly handles integers, floats, and null values. Integer values correctly return unchanged.

---

`856-871`: **Simple but correct implementation of e() function.**

The function properly returns the mathematical constant e from the standard library with appropriate error handling for argument count.

---

`873-894`: **Correct implementation of exp() function with proper error handling.**

The implementation properly handles integers, floats, and null values, with appropriate type checking and error messages.

---

`896-917`: **Correct implementation of floor() function with proper error handling.**

The implementation properly handles integers, floats, and null values. Integer values correctly return unchanged.

---

`919-940`: **Correct implementation of log() function with proper error handling.**

The implementation properly handles integers, floats, and null values. The function uses ln() which is the natural logarithm in Rust.

---

`942-963`: **Correct implementation of log10() function with proper error handling.**

The implementation properly handles integers, floats, and null values, with appropriate type checking and error messages.

---

`964-991`: **Comprehensive implementation of pow() function handling various types.**

The implementation correctly handles all combinations of integer and float arguments for base and exponent, with proper null handling and type checking.

---

`993-1011`: **Correct implementation of rand() function using the rand crate.**

The function properly generates a random number in the range [0.0, 1.0) using the imported rand crate's functionality.

---

`1013-1034`: **Correct implementation of round() function with proper error handling.**

The implementation properly handles integers, floats, and null values. Integer values correctly return unchanged.

---

`1036-1061`: **Thorough implementation of sign() function with special handling for zero.**

The implementation correctly handles integers, floats, and null values. It specifically handles zero for floats to return an integer 0 rather than a float.

---

`1063-1096`: **Robust sqrt() implementation with proper handling of negative inputs.**

The function correctly returns NaN for negative numbers, and properly handles integers, floats, and null values.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T12:31:10Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 3**

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>graph/src/runtime.rs (2)</summary><blockquote>

`882-885`: **`pow` should expect *exactly* two arguments, not “at least”**

The error message claims “expected at least 2”, but the match arm above rejects any call with ≠2 arguments.  
Align the wording to avoid user confusion.

```diff
-                "Received {} arguments to function 'pow', expected at least 2",
+                "Received {} arguments to function 'pow', expected exactly 2",
```

---

`933-937`: **`sign` returns mixed numeric types – consider normalising**

For `Float` inputs you return a `Float` (±1.0) whereas for `Int` inputs you return an `Int`.  
This asymmetry can surprise callers and complicates downstream type-checking.  

Options:
1. Always return `Int` (-1/0/1).  
2. Always return `Float`.  

Pick one and document it; Neo4j’s `sign` returns `Integer`, so option 1 may be safer.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 34b5dd891bdbde7cd3ce5434569d70b4ba612125 and 02a2ad1cb7105c06848d09a58a761255431dfc0b.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `graph/src/runtime.rs` (11 hunks)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T17:23:20Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>graph/src/cypher.rs (1)</summary><blockquote>

`67-83`: **Consider tightening `ExpressionListType` semantics**

Great idea extracting `ExpressionListType` – it makes the call-sites much clearer.  
Two small follow-ups you might want to consider:

1. `OneOrMore` currently relies on the inner loop’s `break` to terminate.  An explicit “end token” (e.g. `None` sentinel) or a post-condition check (see next comment) would make the contract (“at least one expression”) self-contained and easier to reason about.

2. `ZeroOrMoreClosedBy(Token)` moves (`Token`) on every call.  If the enum were
   ```
   ZeroOrMoreClosedBy(&'static Token)
   ```
   you would avoid the move / clone and the large enum size; however this is purely optional since the current derivations are inexpensive compared to parse-time.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 02a2ad1cb7105c06848d09a58a761255431dfc0b and e331ad5b99a5962397c04fddfc9d46e9d5d55e6e.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `graph/src/cypher.rs` (10 hunks)

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: test
* GitHub Check: coverage

</details>

<details>
<summary>🔇 Additional comments (5)</summary><blockquote>

<details>
<summary>graph/src/cypher.rs (5)</summary>

`378-392`: **👍  Nice extraction of `consume_digits`**

Extracting the duplicated digit-scanning loop into `consume_digits` removes ~20 LOC of repetition and centralises the logic.  The boolean flag design cleanly communicates “did we actually consume anything?” and protects the later validation code. Good job!

---

`599-603`: **Verify empty-`DELETE` edge case**

Now that `parse_delete_clause` relies on `ExpressionListType::OneOrMore`, the compiler-level check above becomes important – otherwise a lone `DELETE` will parse as zero expressions and reach runtime before failing.

After applying the validation fix, consider adding a parser test like:

```rust
assert!(Parser::new("DELETE").parse().is_err());
```

---

`564-570`: **Cleaner `CALL` parsing looks good**

Refactoring `CALL` to use the unified `parse_expression_list` eliminates duplicated “consume arguments until `)`” logic and already handles the empty-argument optimisation. Nice polish.

---

`705-709`: **Uniform function-invocation parsing**

Same applause here – using the new helper removes specialised code and keeps the parentheses balancing in one place.  No functional issues spotted.

---

`738-742`: **List literal parsing aligned with new helper**

The change keeps list-literal semantics untouched while improving readability. All good.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T05:43:44Z
user: login: AviAvni
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T07:39:18Z
user: login: AviAvni
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T07:44:40Z

Review comments:
diff_hunk: @@ -1254,3 +1256,194 @@ def test_list_re_replace():
         assert False, "Expected an error"
     except ResponseError as e:
         assert "Invalid regex," in str(e)
+
+
+def test_abs():
+    res = query("RETURN abs(1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(-1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(0) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN abs(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN abs({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN abs(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'abs', expected at most 1" in str(e)
+
+
+def test_ceil():
+    res = query("RETURN ceil(1.1) AS name")
+    assert res.result_set == [[2]]
+
+    res = query("RETURN ceil(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN ceil(-1.1) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN ceil({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN ceil(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'ceil', expected at most 1" in str(e)
+
+
+def test_e():
+    res = query("RETURN e() AS name")
+    assert res.result_set == [[2.71828182845905e0]]
+
+    # wrong number of args
+    try:
+        query("RETURN e(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'e', expected at most 0" in str(e)
+
+
+def test_exp():
+    res = query("RETURN exp(1) AS name")
+    assert res.result_set == [[2.71828182845905]]
+
+    res = query("RETURN exp(0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN exp(-1) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(-1.0) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN exp({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN exp(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'exp', expected at most 1" in str(e)
+
+
+def test_floor():
+    res = query("RETURN floor(1.1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(-1.1) AS name")
+    assert res.result_set == [[-2]]
+
+    res = query("RETURN floor(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN floor(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN floor({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN floor(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'floor', expected at most 1" in str(e)
+
+
+def test_log():
+    res = query("RETURN log(1) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN log(0) AS name")
+    assert res.result_set == [[float('-inf')]]
+
+    res = query("RETURN log(-1) AS name")
+    v = res.result_set[0][0]
+    assert math.isnan(res.result_set[0][0])
+
+    res = query("RETURN log(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN log({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN log(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'log', expected at most 1" in str(e)
+
+
+def test_log10():
+    res = query("RETURN log10(1) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN log10(0) AS name")
+    assert res.result_set == [[float('-inf')]]
+
+    res = query("RETURN log10(-1) AS name")
+    v = res.result_set[0][0]
+    assert math.isnan(res.result_set[0][0])
+
+    res = query("RETURN log10(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN log10({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN log10(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'log10', expected at most 1" in str(e)
path: tests/test_e2e.py
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Well-designed test cases for log10() with special values, but contains unused variable.**

Similar to the log() test, this test correctly verifies special cases but has an unused variable 'v' on line 1431.

```diff
-    v = res.result_set[0][0]
     assert math.isnan(res.result_set[0][0])
```

And the same assertion issue:
```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
def test_log10():
    res = query("RETURN log10(1) AS name")
    assert res.result_set == [[0]]

    res = query("RETURN log10(0) AS name")
    assert res.result_set == [[float('-inf')]]

    res = query("RETURN log10(-1) AS name")
    assert math.isnan(res.result_set[0][0])

    res = query("RETURN log10(null) AS name")
    assert res.result_set == [[None]]

    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
        try:
            query(f"RETURN log10({value}) AS r")
            raise AssertionError("Expected an error")
        except ResponseError as e:
            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)

    # wrong number of args
    try:
        query("RETURN log10(1, 2) AS name")
        raise AssertionError("Expected an error")
    except ResponseError as e:
        assert "Received 2 arguments to function 'log10', expected at most 1" in str(e)
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1431-1431: Local variable `v` is assigned to but never used

Remove assignment to unused variable `v`

(F841)

---

1440-1440: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1447-1447: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-29T09:24:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1254,3 +1256,194 @@ def test_list_re_replace():
         assert False, "Expected an error"
     except ResponseError as e:
         assert "Invalid regex," in str(e)
+
+
+def test_abs():
+    res = query("RETURN abs(1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(-1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(0) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN abs(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN abs({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN abs(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'abs', expected at most 1" in str(e)
+
+
+def test_ceil():
+    res = query("RETURN ceil(1.1) AS name")
+    assert res.result_set == [[2]]
+
+    res = query("RETURN ceil(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN ceil(-1.1) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN ceil({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN ceil(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'ceil', expected at most 1" in str(e)
+
+
+def test_e():
+    res = query("RETURN e() AS name")
+    assert res.result_set == [[2.71828182845905e0]]
+
+    # wrong number of args
+    try:
+        query("RETURN e(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'e', expected at most 0" in str(e)
+
+
+def test_exp():
+    res = query("RETURN exp(1) AS name")
+    assert res.result_set == [[2.71828182845905]]
+
+    res = query("RETURN exp(0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN exp(-1) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(-1.0) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN exp({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN exp(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'exp', expected at most 1" in str(e)
+
+
+def test_floor():
+    res = query("RETURN floor(1.1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(-1.1) AS name")
+    assert res.result_set == [[-2]]
+
+    res = query("RETURN floor(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN floor(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN floor({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN floor(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'floor', expected at most 1" in str(e)
+
+
+def test_log():
+    res = query("RETURN log(1) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN log(0) AS name")
+    assert res.result_set == [[float('-inf')]]
+
+    res = query("RETURN log(-1) AS name")
+    v = res.result_set[0][0]
+    assert math.isnan(res.result_set[0][0])
+
+    res = query("RETURN log(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN log({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN log(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'log', expected at most 1" in str(e)
+
path: tests/test_e2e.py
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Well-designed test cases for log() with special values, but contains unused variable.**

The test correctly verifies log(1)=0, log(0)=-infinity, and log(-1)=NaN. There's an unused variable 'v' on line 1402 that should be removed.

```diff
-    v = res.result_set[0][0]
     assert math.isnan(res.result_set[0][0])
```

Also, the same assertion issue exists:
```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
def test_log():
    res = query("RETURN log(1) AS name")
    assert res.result_set == [[0]]

    res = query("RETURN log(0) AS name")
    assert res.result_set == [[float('-inf')]]

    res = query("RETURN log(-1) AS name")
    assert math.isnan(res.result_set[0][0])

    res = query("RETURN log(null) AS name")
    assert res.result_set == [[None]]

    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
        try:
            query(f"RETURN log({value}) AS r")
            raise AssertionError("Expected an error")
        except ResponseError as e:
            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)

    # wrong number of args
    try:
        query("RETURN log(1, 2) AS name")
        raise AssertionError("Expected an error")
    except ResponseError as e:
        assert "Received 2 arguments to function 'log', expected at most 1" in str(e)
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1402-1402: Local variable `v` is assigned to but never used

Remove assignment to unused variable `v`

(F841)

---

1411-1411: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1418-1418: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-29T09:24:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1254,3 +1256,240 @@ def test_list_re_replace():
         assert False, "Expected an error"
     except ResponseError as e:
         assert "Invalid regex," in str(e)
+
+
+def test_abs():
+    res = query("RETURN abs(1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(-1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(0) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN abs(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN abs({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN abs(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'abs', expected at most 1" in str(e)
+
+
+def test_ceil():
+    res = query("RETURN ceil(1.1) AS name")
+    assert res.result_set == [[2]]
+
+    res = query("RETURN ceil(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN ceil(-1.1) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN ceil({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN ceil(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'ceil', expected at most 1" in str(e)
+
+
+def test_e():
+    res = query("RETURN e() AS name")
+    assert res.result_set == [[2.71828182845905e0]]
+
+    # wrong number of args
+    try:
+        query("RETURN e(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'e', expected at most 0" in str(e)
+
path: tests/test_e2e.py
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Comprehensive tests for e() function with assertion improvement needed.**

The tests verify the mathematical constant e is returned and validate error handling for incorrect argument counts.


Replace assertion with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
def test_e():
    res = query("RETURN e() AS name")
    assert res.result_set == [[2.71828182845905e0]]

    # wrong number of args
    try:
        query("RETURN e(1) AS name")
        raise AssertionError("Expected an error")
    except ResponseError as e:
        assert "Received 1 arguments to function 'e', expected at most 0" in str(e)
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1327-1327: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-29T10:13:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1254,3 +1256,240 @@ def test_list_re_replace():
         assert False, "Expected an error"
     except ResponseError as e:
         assert "Invalid regex," in str(e)
+
+
+def test_abs():
+    res = query("RETURN abs(1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(-1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(0) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN abs(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN abs({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN abs(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'abs', expected at most 1" in str(e)
+
+
+def test_ceil():
+    res = query("RETURN ceil(1.1) AS name")
+    assert res.result_set == [[2]]
+
+    res = query("RETURN ceil(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN ceil(-1.1) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN ceil({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN ceil(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'ceil', expected at most 1" in str(e)
+
+
+def test_e():
+    res = query("RETURN e() AS name")
+    assert res.result_set == [[2.71828182845905e0]]
+
+    # wrong number of args
+    try:
+        query("RETURN e(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'e', expected at most 0" in str(e)
+
+
+def test_exp():
+    res = query("RETURN exp(1) AS name")
+    assert res.result_set == [[2.71828182845905]]
+
+    res = query("RETURN exp(0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN exp(-1) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(-1.0) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN exp({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN exp(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'exp', expected at most 1" in str(e)
+
+
+def test_floor():
+    res = query("RETURN floor(1.1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(-1.1) AS name")
+    assert res.result_set == [[-2]]
+
+    res = query("RETURN floor(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN floor(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN floor({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN floor(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'floor', expected at most 1" in str(e)
+
path: tests/test_e2e.py
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Comprehensive tests for floor() function with assertion improvement needed.**

The tests thoroughly verify the floor() function's behavior with various floating-point values and integer edge cases.


Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
def test_floor():
    res = query("RETURN floor(1.1) AS name")
    assert res.result_set == [[1]]

    res = query("RETURN floor(1.0) AS name")
    assert res.result_set == [[1]]

    res = query("RETURN floor(-1.1) AS name")
    assert res.result_set == [[-2]]

    res = query("RETURN floor(-1.0) AS name")
    assert res.result_set == [[-1]]

    res = query("RETURN floor(null) AS name")
    assert res.result_set == [[None]]

    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
        try:
            query(f"RETURN floor({value}) AS r")
            raise AssertionError("Expected an error")
        except ResponseError as e:
            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)

    # wrong number of args
    try:
        query("RETURN floor(1, 2) AS name")
        raise AssertionError("Expected an error")
    except ResponseError as e:
        assert "Received 2 arguments to function 'floor', expected at most 1" in str(e)
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1382-1382: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1389-1389: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-29T10:13:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1254,3 +1256,240 @@ def test_list_re_replace():
         assert False, "Expected an error"
     except ResponseError as e:
         assert "Invalid regex," in str(e)
+
+
+def test_abs():
+    res = query("RETURN abs(1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(-1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(0) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN abs(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN abs({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN abs(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'abs', expected at most 1" in str(e)
+
path: tests/test_e2e.py
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Comprehensive tests for abs() function with assertion improvement needed.**

The tests thoroughly verify the abs() function's behavior with positive, negative, and null values, as well as error handling for invalid types and argument counts.


Replace assertions with proper AssertionError raising to avoid issues with Python optimization (-O flag):

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
def test_abs():
    res = query("RETURN abs(1) AS name")
    assert res.result_set == [[1]]

    res = query("RETURN abs(-1) AS name")
    assert res.result_set == [[1]]

    res = query("RETURN abs(0) AS name")
    assert res.result_set == [[0]]

    res = query("RETURN abs(null) AS name")
    assert res.result_set == [[None]]

    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
        try:
            query(f"RETURN abs({value}) AS r")
            raise AssertionError("Expected an error")
        except ResponseError as e:
            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)

    # wrong number of args
    try:
        query("RETURN abs(1, 2) AS name")
        assert False, "Expected an error"
    except ResponseError as e:
        assert "Received 2 arguments to function 'abs', expected at most 1" in str(e)
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1277-1277: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1284-1284: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-29T10:13:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1254,3 +1256,240 @@ def test_list_re_replace():
         assert False, "Expected an error"
     except ResponseError as e:
         assert "Invalid regex," in str(e)
+
+
+def test_abs():
+    res = query("RETURN abs(1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(-1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(0) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN abs(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN abs({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN abs(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'abs', expected at most 1" in str(e)
+
+
+def test_ceil():
+    res = query("RETURN ceil(1.1) AS name")
+    assert res.result_set == [[2]]
+
+    res = query("RETURN ceil(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN ceil(-1.1) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN ceil({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN ceil(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'ceil', expected at most 1" in str(e)
+
path: tests/test_e2e.py
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Comprehensive tests for ceil() function with assertion improvement needed.**

The tests thoroughly verify the ceil() function's behavior with various floating-point values and integer edge cases.


Replace assertions with proper AssertionError raising to avoid issues with Python optimization (-O flag):

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```


> Committable suggestion skipped: line range outside the PR's diff.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1308-1308: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1315-1315: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-29T10:13:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1254,3 +1256,238 @@ def test_list_re_replace():
         assert False, "Expected an error"
     except ResponseError as e:
         assert "Invalid regex," in str(e)
+
+
+def test_abs():
+    res = query("RETURN abs(1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(-1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(0) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN abs(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN abs({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN abs(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'abs', expected at most 1" in str(e)
+
+
+def test_ceil():
+    res = query("RETURN ceil(1.1) AS name")
+    assert res.result_set == [[2]]
+
+    res = query("RETURN ceil(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN ceil(-1.1) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN ceil({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN ceil(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'ceil', expected at most 1" in str(e)
+
+
+def test_e():
+    res = query("RETURN e() AS name")
+    assert res.result_set == [[2.71828182845905e0]]
+
+    # wrong number of args
+    try:
+        query("RETURN e(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'e', expected at most 0" in str(e)
+
+
+def test_exp():
+    res = query("RETURN exp(1) AS name")
+    assert res.result_set == [[2.71828182845905]]
+
+    res = query("RETURN exp(0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN exp(-1) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(-1.0) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN exp({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN exp(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'exp', expected at most 1" in str(e)
+
path: tests/test_e2e.py
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Comprehensive tests for exp() function with assertion improvement needed.**

The tests verify exp(1) returns Euler's number, exp(0) returns 1, and handles various inputs including negative values.

Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
def test_exp():
    res = query("RETURN exp(1) AS name")
    assert res.result_set == [[2.71828182845905]]

    res = query("RETURN exp(0) AS name")
    assert res.result_set == [[1]]

    res = query("RETURN exp(-1) AS name")
    assert res.result_set == [[0.367879441171442]]

    res = query("RETURN exp(-1.0) AS name")
    assert res.result_set == [[0.367879441171442]]

    res = query("RETURN exp(null) AS name")
    assert res.result_set == [[None]]

    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
        try:
            query(f"RETURN exp({value}) AS r")
            raise AssertionError("Expected an error")
        except ResponseError as e:
            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)

    # wrong number of args
    try:
        query("RETURN exp(1, 2) AS name")
        raise AssertionError("Expected an error")
    except ResponseError as e:
        assert "Received 2 arguments to function 'exp', expected at most 1" in str(e)
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1351-1351: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1358-1358: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-29T10:16:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1254,3 +1256,282 @@ def test_list_re_replace():
         assert False, "Expected an error"
     except ResponseError as e:
         assert "Invalid regex," in str(e)
+
+
+def test_abs():
+    res = query("RETURN abs(1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(-1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(0) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN abs(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN abs({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN abs(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'abs', expected at most 1" in str(e)
+
+
+def test_ceil():
+    res = query("RETURN ceil(1.1) AS name")
+    assert res.result_set == [[2]]
+
+    res = query("RETURN ceil(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN ceil(-1.1) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN ceil({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN ceil(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'ceil', expected at most 1" in str(e)
+
+
+def test_e():
+    res = query("RETURN e() AS name")
+    assert res.result_set == [[2.71828182845905e0]]
+
+    # wrong number of args
+    try:
+        query("RETURN e(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'e', expected at most 0" in str(e)
+
+
+def test_exp():
+    res = query("RETURN exp(1) AS name")
+    assert res.result_set == [[2.71828182845905]]
+
+    res = query("RETURN exp(0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN exp(-1) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(-1.0) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN exp({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN exp(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'exp', expected at most 1" in str(e)
+
+
+def test_floor():
+    res = query("RETURN floor(1.1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(-1.1) AS name")
+    assert res.result_set == [[-2]]
+
+    res = query("RETURN floor(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN floor(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN floor({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN floor(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'floor', expected at most 1" in str(e)
+
+
+def test_log():
+    res = query("RETURN log(1) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN log(0) AS name")
+    assert res.result_set == [[float('-inf')]]
+
+    res = query("RETURN log(-1) AS name")
+    assert math.isnan(res.result_set[0][0])
+
+    res = query("RETURN log(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN log({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN log(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'log', expected at most 1" in str(e)
+
+
+def test_log10():
+    res = query("RETURN log10(1) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN log10(0) AS name")
+    assert res.result_set == [[float('-inf')]]
+
+    res = query("RETURN log10(-1) AS name")
+    assert math.isnan(res.result_set[0][0])
+
+    res = query("RETURN log10(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN log10({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN log10(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'log10', expected at most 1" in str(e)
+
path: tests/test_e2e.py
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Well-designed test cases for log10() with special values, but contains unused variable.**

Similar to the log() test, this test correctly verifies special cases but has an unused variable 'v' on line 1431.


```diff
-    v = res.result_set[0][0]
     assert math.isnan(res.result_set[0][0])
```

Also, replace assertions with proper AssertionError raising:
```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```


> Committable suggestion skipped: line range outside the PR's diff.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1438-1438: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1445-1445: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-29T12:01:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1254,3 +1256,282 @@ def test_list_re_replace():
         assert False, "Expected an error"
     except ResponseError as e:
         assert "Invalid regex," in str(e)
+
+
+def test_abs():
+    res = query("RETURN abs(1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(-1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(0) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN abs(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN abs({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN abs(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'abs', expected at most 1" in str(e)
+
+
+def test_ceil():
+    res = query("RETURN ceil(1.1) AS name")
+    assert res.result_set == [[2]]
+
+    res = query("RETURN ceil(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN ceil(-1.1) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN ceil({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN ceil(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'ceil', expected at most 1" in str(e)
+
+
+def test_e():
+    res = query("RETURN e() AS name")
+    assert res.result_set == [[2.71828182845905e0]]
+
+    # wrong number of args
+    try:
+        query("RETURN e(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'e', expected at most 0" in str(e)
+
+
+def test_exp():
+    res = query("RETURN exp(1) AS name")
+    assert res.result_set == [[2.71828182845905]]
+
+    res = query("RETURN exp(0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN exp(-1) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(-1.0) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN exp({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN exp(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'exp', expected at most 1" in str(e)
+
+
+def test_floor():
+    res = query("RETURN floor(1.1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(-1.1) AS name")
+    assert res.result_set == [[-2]]
+
+    res = query("RETURN floor(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN floor(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN floor({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN floor(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'floor', expected at most 1" in str(e)
+
+
+def test_log():
+    res = query("RETURN log(1) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN log(0) AS name")
+    assert res.result_set == [[float('-inf')]]
+
+    res = query("RETURN log(-1) AS name")
+    assert math.isnan(res.result_set[0][0])
+
+    res = query("RETURN log(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN log({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN log(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'log', expected at most 1" in str(e)
+
+
+def test_log10():
+    res = query("RETURN log10(1) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN log10(0) AS name")
+    assert res.result_set == [[float('-inf')]]
+
+    res = query("RETURN log10(-1) AS name")
+    assert math.isnan(res.result_set[0][0])
+
+    res = query("RETURN log10(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN log10({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN log10(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'log10', expected at most 1" in str(e)
+
+
+def test_pow():
+    res = query("RETURN pow(2, 3) AS name")
+    assert res.result_set == [[8]]
+
+    res = query("RETURN pow(2, -3) AS name")
+    assert res.result_set == [[0.125]]
+
+    res = query("RETURN pow(2, 0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN pow(-2, 3) AS name")
+    assert res.result_set == [[-8]]
+
+    res = query("RETURN pow(-2, -3) AS name")
+    assert res.result_set == [[-0.125]]
+
+    res = query("RETURN pow(-2, 0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN pow(null, 3) AS name")
+    assert res.result_set == [[None]]
+
+    res = query("RETURN pow(3, null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN pow({value}, 3) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+        try:
+            query(f"RETURN pow(2, {value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN pow(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'pow', expected at least 2" in str(e)
+
path: tests/test_e2e.py
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Comprehensive test suite for pow() function covering various edge cases.**

The test verifies positive/negative bases, positive/negative exponents, zero exponents, and null handling.


Replace assertions with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
def test_pow():
    res = query("RETURN pow(2, 3) AS name")
    assert res.result_set == [[8]]

    res = query("RETURN pow(2, -3) AS name")
    assert res.result_set == [[0.125]]

    res = query("RETURN pow(2, 0) AS name")
    assert res.result_set == [[1]]

    res = query("RETURN pow(-2, 3) AS name")
    assert res.result_set == [[-8]]

    res = query("RETURN pow(-2, -3) AS name")
    assert res.result_set == [[-0.125]]

    res = query("RETURN pow(-2, 0) AS name")
    assert res.result_set == [[1]]

    res = query("RETURN pow(null, 3) AS name")
    assert res.result_set == [[None]]

    res = query("RETURN pow(3, null) AS name")
    assert res.result_set == [[None]]

    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
        try:
            query(f"RETURN pow({value}, 3) AS r")
            raise AssertionError("Expected an error")
        except ResponseError as e:
            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)

        try:
            query(f"RETURN pow(2, {value}) AS r")
            raise AssertionError("Expected an error")
        except ResponseError as e:
            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)

    # wrong number of args
    try:
        query("RETURN pow(1) AS name")
        raise AssertionError("Expected an error")
    except ResponseError as e:
        assert "Received 1 arguments to function 'pow', expected at least 2" in str(e)
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1478-1478: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1484-1484: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1491-1491: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-29T12:01:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1254,3 +1256,317 @@ def test_list_re_replace():
         assert False, "Expected an error"
     except ResponseError as e:
         assert "Invalid regex," in str(e)
+
+
+def test_abs():
+    res = query("RETURN abs(1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(-1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(0) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN abs(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN abs({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN abs(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'abs', expected at most 1" in str(e)
+
+
+def test_ceil():
+    res = query("RETURN ceil(1.1) AS name")
+    assert res.result_set == [[2]]
+
+    res = query("RETURN ceil(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN ceil(-1.1) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN ceil({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN ceil(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'ceil', expected at most 1" in str(e)
+
+
+def test_e():
+    res = query("RETURN e() AS name")
+    assert res.result_set == [[2.71828182845905e0]]
+
+    # wrong number of args
+    try:
+        query("RETURN e(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'e', expected at most 0" in str(e)
+
+
+def test_exp():
+    res = query("RETURN exp(1) AS name")
+    assert res.result_set == [[2.71828182845905]]
+
+    res = query("RETURN exp(0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN exp(-1) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(-1.0) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN exp({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN exp(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'exp', expected at most 1" in str(e)
+
+
+def test_floor():
+    res = query("RETURN floor(1.1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(-1.1) AS name")
+    assert res.result_set == [[-2]]
+
+    res = query("RETURN floor(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN floor(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN floor({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN floor(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'floor', expected at most 1" in str(e)
+
+
+def test_log():
+    res = query("RETURN log(1) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN log(0) AS name")
+    assert res.result_set == [[float('-inf')]]
+
+    res = query("RETURN log(-1) AS name")
+    assert math.isnan(res.result_set[0][0])
+
+    res = query("RETURN log(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN log({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN log(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'log', expected at most 1" in str(e)
+
+
+def test_log10():
+    res = query("RETURN log10(1) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN log10(0) AS name")
+    assert res.result_set == [[float('-inf')]]
+
+    res = query("RETURN log10(-1) AS name")
+    assert math.isnan(res.result_set[0][0])
+
+    res = query("RETURN log10(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN log10({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN log10(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'log10', expected at most 1" in str(e)
+
+
+def test_pow():
+    res = query("RETURN pow(2, 3) AS name")
+    assert res.result_set == [[8]]
+
+    res = query("RETURN pow(2, -3) AS name")
+    assert res.result_set == [[0.125]]
+
+    res = query("RETURN pow(2, 0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN pow(-2, 3) AS name")
+    assert res.result_set == [[-8]]
+
+    res = query("RETURN pow(-2, -3) AS name")
+    assert res.result_set == [[-0.125]]
+
+    res = query("RETURN pow(-2, 0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN pow(null, 3) AS name")
+    assert res.result_set == [[None]]
+
+    res = query("RETURN pow(3, null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN pow({value}, 3) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+        try:
+            query(f"RETURN pow(2, {value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN pow(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'pow', expected at least 2" in str(e)
+
+
+def test_rand():
+    res = query("RETURN rand() AS name", write=True)
+    assert res.result_set[0][0] >= 0.0
+    assert res.result_set[0][0] < 1.0
+
+    # wrong number of args
+    try:
+        query("RETURN rand(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'rand', expected at most 0" in str(e)
+
+
+def test_round():
+    res = query("RETURN round(1.1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN round(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN round(-1.1) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN round(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN round(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN round({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN round(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'round', expected at most 1" in str(e)
+
path: tests/test_e2e.py
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Thorough round() function tests covering all rounding scenarios.**

The tests verify rounding behavior for positive and negative values, handling of integers, and null inputs.

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
def test_round():
    res = query("RETURN round(1.1) AS name")
    assert res.result_set == [[1]]

    res = query("RETURN round(1.0) AS name")
    assert res.result_set == [[1]]

    res = query("RETURN round(-1.1) AS name")
    assert res.result_set == [[-1]]

    res = query("RETURN round(-1.0) AS name")
    assert res.result_set == [[-1]]

    res = query("RETURN round(null) AS name")
    assert res.result_set == [[None]]

    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
        try:
            query(f"RETURN round({value}) AS r")
-           assert False, "Expected an error"
+           raise AssertionError("Expected an error")
        except ResponseError as e:
            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)

    # wrong number of args
    try:
        query("RETURN round(1, 2) AS name")
-       assert False, "Expected an error"
+       raise AssertionError("Expected an error")
    except ResponseError as e:
        assert "Received 2 arguments to function 'round', expected at most 1" in str(e)
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1528-1528: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1535-1535: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Addressed in commit 34b5dd8
created_at: 2025-04-29T12:17:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1254,3 +1256,317 @@
         assert False, "Expected an error"
     except ResponseError as e:
         assert "Invalid regex," in str(e)
+
+
+def test_abs():
+    res = query("RETURN abs(1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(-1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(0) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN abs(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN abs({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN abs(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'abs', expected at most 1" in str(e)
+
+
+def test_ceil():
+    res = query("RETURN ceil(1.1) AS name")
+    assert res.result_set == [[2]]
+
+    res = query("RETURN ceil(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN ceil(-1.1) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN ceil({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN ceil(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'ceil', expected at most 1" in str(e)
+
+
+def test_e():
+    res = query("RETURN e() AS name")
+    assert res.result_set == [[2.71828182845905e0]]
+
+    # wrong number of args
+    try:
+        query("RETURN e(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'e', expected at most 0" in str(e)
+
+
+def test_exp():
+    res = query("RETURN exp(1) AS name")
+    assert res.result_set == [[2.71828182845905]]
+
+    res = query("RETURN exp(0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN exp(-1) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(-1.0) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN exp({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN exp(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'exp', expected at most 1" in str(e)
+
+
+def test_floor():
+    res = query("RETURN floor(1.1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(-1.1) AS name")
+    assert res.result_set == [[-2]]
+
+    res = query("RETURN floor(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN floor(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN floor({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN floor(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'floor', expected at most 1" in str(e)
+
+
+def test_log():
+    res = query("RETURN log(1) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN log(0) AS name")
+    assert res.result_set == [[float('-inf')]]
+
+    res = query("RETURN log(-1) AS name")
+    assert math.isnan(res.result_set[0][0])
+
+    res = query("RETURN log(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN log({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN log(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'log', expected at most 1" in str(e)
+
+
+def test_log10():
+    res = query("RETURN log10(1) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN log10(0) AS name")
+    assert res.result_set == [[float('-inf')]]
+
+    res = query("RETURN log10(-1) AS name")
+    assert math.isnan(res.result_set[0][0])
+
+    res = query("RETURN log10(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN log10({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN log10(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'log10', expected at most 1" in str(e)
+
+
+def test_pow():
+    res = query("RETURN pow(2, 3) AS name")
+    assert res.result_set == [[8]]
+
+    res = query("RETURN pow(2, -3) AS name")
+    assert res.result_set == [[0.125]]
+
+    res = query("RETURN pow(2, 0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN pow(-2, 3) AS name")
+    assert res.result_set == [[-8]]
+
+    res = query("RETURN pow(-2, -3) AS name")
+    assert res.result_set == [[-0.125]]
+
+    res = query("RETURN pow(-2, 0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN pow(null, 3) AS name")
+    assert res.result_set == [[None]]
+
+    res = query("RETURN pow(3, null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN pow({value}, 3) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+        try:
+            query(f"RETURN pow(2, {value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN pow(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'pow', expected at least 2" in str(e)
+
+
+def test_rand():
+    res = query("RETURN rand() AS name", write=True)
+    assert res.result_set[0][0] >= 0.0
+    assert res.result_set[0][0] < 1.0
+
+    # wrong number of args
+    try:
+        query("RETURN rand(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'rand', expected at most 0" in str(e)
+
path: tests/test_e2e.py
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Good basic test for rand() function checking output range.**

The test verifies that rand() returns a value in the range [0.0, 1.0), which is the expected behavior for a random number generator.

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
def test_rand():
    res = query("RETURN rand() AS name", write=True)
    assert res.result_set[0][0] >= 0.0
    assert res.result_set[0][0] < 1.0

    # wrong number of args
    try:
        query("RETURN rand(1) AS name")
        raise AssertionError("Expected an error")
    except ResponseError as e:
        assert "Received 1 arguments to function 'rand', expected at most 0" in str(e)
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1504-1504: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-29T12:17:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1254,3 +1256,345 @@ def test_list_re_replace():
         assert False, "Expected an error"
     except ResponseError as e:
         assert "Invalid regex," in str(e)
+
+
+def test_abs():
+    res = query("RETURN abs(1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(-1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN abs(0) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN abs(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN abs({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN abs(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'abs', expected at most 1" in str(e)
+
+
+def test_ceil():
+    res = query("RETURN ceil(1.1) AS name")
+    assert res.result_set == [[2]]
+
+    res = query("RETURN ceil(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN ceil(-1.1) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN ceil(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN ceil({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN ceil(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'ceil', expected at most 1" in str(e)
+
+
+def test_e():
+    res = query("RETURN e() AS name")
+    assert res.result_set == [[2.71828182845905e0]]
+
+    # wrong number of args
+    try:
+        query("RETURN e(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'e', expected at most 0" in str(e)
+
+
+def test_exp():
+    res = query("RETURN exp(1) AS name")
+    assert res.result_set == [[2.71828182845905]]
+
+    res = query("RETURN exp(0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN exp(-1) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(-1.0) AS name")
+    assert res.result_set == [[0.367879441171442]]
+
+    res = query("RETURN exp(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN exp({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN exp(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'exp', expected at most 1" in str(e)
+
+
+def test_floor():
+    res = query("RETURN floor(1.1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN floor(-1.1) AS name")
+    assert res.result_set == [[-2]]
+
+    res = query("RETURN floor(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN floor(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN floor({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN floor(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'floor', expected at most 1" in str(e)
+
+
+def test_log():
+    res = query("RETURN log(1) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN log(0) AS name")
+    assert res.result_set == [[float('-inf')]]
+
+    res = query("RETURN log(-1) AS name")
+    assert math.isnan(res.result_set[0][0])
+
+    res = query("RETURN log(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN log({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN log(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'log', expected at most 1" in str(e)
+
+
+def test_log10():
+    res = query("RETURN log10(1) AS name")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN log10(0) AS name")
+    assert res.result_set == [[float('-inf')]]
+
+    res = query("RETURN log10(-1) AS name")
+    assert math.isnan(res.result_set[0][0])
+
+    res = query("RETURN log10(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN log10({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN log10(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'log10', expected at most 1" in str(e)
+
+
+def test_pow():
+    res = query("RETURN pow(2, 3) AS name")
+    assert res.result_set == [[8]]
+
+    res = query("RETURN pow(2, -3) AS name")
+    assert res.result_set == [[0.125]]
+
+    res = query("RETURN pow(2, 0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN pow(-2, 3) AS name")
+    assert res.result_set == [[-8]]
+
+    res = query("RETURN pow(-2, -3) AS name")
+    assert res.result_set == [[-0.125]]
+
+    res = query("RETURN pow(-2, 0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN pow(null, 3) AS name")
+    assert res.result_set == [[None]]
+
+    res = query("RETURN pow(3, null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN pow({value}, 3) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+        try:
+            query(f"RETURN pow(2, {value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN pow(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'pow', expected at least 2" in str(e)
+
+
+def test_rand():
+    res = query("RETURN rand() AS name", write=True)
+    assert res.result_set[0][0] >= 0.0
+    assert res.result_set[0][0] < 1.0
+
+    # wrong number of args
+    try:
+        query("RETURN rand(1) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 1 arguments to function 'rand', expected at most 0" in str(e)
+
+
+def test_round():
+    res = query("RETURN round(1.1) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN round(1.0) AS name")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN round(-1.1) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN round(-1.0) AS name")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN round(null) AS name")
+    assert res.result_set == [[None]]
+
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN round({value}) AS r")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
+    # wrong number of args
+    try:
+        query("RETURN round(1, 2) AS name")
+        assert False, "Expected an error"
+    except ResponseError as e:
+        assert "Received 2 arguments to function 'round', expected at most 1" in str(e)
+
+
+def test_sign():
+    # Test positive numbers
+    res = query("RETURN sign(5) AS result")
+    assert res.result_set == [[1]]
+
+    res = query("RETURN sign(0.1) AS result")
+    assert res.result_set == [[1]]
+
+    # Test zero
+    res = query("RETURN sign(0) AS result")
+    assert res.result_set == [[0]]
+
+    res = query("RETURN sign(0.0) AS result")
+    assert res.result_set == [[0]]
+
+    # Test negative numbers
+    res = query("RETURN sign(-5) AS result")
+    assert res.result_set == [[-1]]
+
+    res = query("RETURN sign(-0.1) AS result")
+    assert res.result_set == [[-1]]
+
+    # Test null
+    res = query("RETURN sign(null) AS result")
+    assert res.result_set == [[None]]
+
+    # Type mismatch
+    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
+        try:
+            query(f"RETURN sign({value}) AS result")
+            assert False, "Expected an error"
+        except ResponseError as e:
+            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
+
path: tests/test_e2e.py
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Comprehensive test suite for sign() function covering all cases.**

The test properly checks positive, zero, and negative cases for both integers and floats, with proper null handling and type validation.

Replace assertion with proper AssertionError raising:

```diff
-            assert False, "Expected an error"
+            raise AssertionError("Expected an error")
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
def test_sign():
    # Test positive numbers
    res = query("RETURN sign(5) AS result")
    assert res.result_set == [[1]]

    res = query("RETURN sign(0.1) AS result")
    assert res.result_set == [[1]]

    # Test zero
    res = query("RETURN sign(0) AS result")
    assert res.result_set == [[0]]

    res = query("RETURN sign(0.0) AS result")
    assert res.result_set == [[0]]

    # Test negative numbers
    res = query("RETURN sign(-5) AS result")
    assert res.result_set == [[-1]]

    res = query("RETURN sign(-0.1) AS result")
    assert res.result_set == [[-1]]

    # Test null
    res = query("RETURN sign(null) AS result")
    assert res.result_set == [[None]]

    # Type mismatch
    for value, name in [(True, 'Boolean'), (False, 'Boolean'), ({}, 'Map'), ([], 'List')]:
        try:
            query(f"RETURN sign({value}) AS result")
            raise AssertionError("Expected an error")
        except ResponseError as e:
            assert f"Type mismatch: expected Integer, Float, or Null but was {name}" in str(e)
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Ruff (0.8.2)</summary>

1570-1570: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-29T12:31:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,11 +1,12 @@
 use crate::{
     ast::QueryExprIR, graph::Graph, matrix::Iter, planner::IR, value::Contains, value::Value,
 };
+use rand::Rng;
path: graph/src/runtime.rs
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Incorrect `rand` import – use the thread-local RNG instead**

`rand::Rng` only brings the trait into scope; the free function `rand::rng()` you later call does not exist (hence a compile error).  
Import `thread_rng` (and optionally `Rng` for the trait) instead.

```diff
-use rand::Rng;
+use rand::{thread_rng, Rng};
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
-use rand::Rng;
+use rand::{thread_rng, Rng};
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-29T17:23:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -691,106 +633,349 @@
                 .collect()
         }
 
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::List(vec), Value::String(s)] => {
-                    let result = to_string_vec(vec);
-                    result.map(|strings| Value::String(strings.join(s)))
-                }
-                [Value::List(vec)] => {
-                    let result = to_string_vec(vec);
-                    result.map(|strings| Value::String(strings.join("")))
-                }
-                [Value::Null, _] => Ok(Value::Null),
-                [arg1, _arg2] => Err(format!(
-                    "Type mismatch: expected List or Null but was {}",
-                    arg1.name()
-                )),
-                args => Err(format!(
-                    "Received {} arguments to function 'string.join', expected at most 2",
-                    args.len()
-                )),
-            },
-            _ => unreachable!(),
+        match args.as_slice() {
+            [Value::List(vec), Value::String(s)] => {
+                let result = to_string_vec(vec);
+                result.map(|strings| Value::String(strings.join(s)))
+            }
+            [Value::List(vec)] => {
+                let result = to_string_vec(vec);
+                result.map(|strings| Value::String(strings.join("")))
+            }
+            [Value::Null, _] => Ok(Value::Null),
+            [arg1, _arg2] => Err(format!(
+                "Type mismatch: expected List or Null but was {}",
+                arg1.name()
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'string.join', expected at most 2",
+                args.len()
+            )),
         }
     }
 
     fn string_match_reg_ex(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::String(text), Value::String(pattern)] => match regex::Regex::new(pattern) {
-                    Ok(re) => {
-                        let mut all_matches = Vec::new();
-                        for caps in re.captures_iter(text) {
-                            for i in 0..caps.len() {
-                                if let Some(m) = caps.get(i) {
-                                    all_matches.push(Value::String(m.as_str().to_string()));
-                                }
+        match args.as_slice() {
+            [Value::String(text), Value::String(pattern)] => match regex::Regex::new(pattern) {
+                Ok(re) => {
+                    let mut all_matches = Vec::new();
+                    for caps in re.captures_iter(text) {
+                        for i in 0..caps.len() {
+                            if let Some(m) = caps.get(i) {
+                                all_matches.push(Value::String(m.as_str().to_string()));
                             }
                         }
-                        Ok(Value::List(all_matches))
                     }
-                    Err(e) => Err(format!("Invalid regex, {e}")),
-                },
-                [Value::Null, _] | [_, Value::Null] => Ok(Value::List(vec![])),
-                [Value::String(_), arg2] => Err(format!(
-                    "Type mismatch: expected String or Null but was {}",
-                    arg2.name(),
-                )),
-                [arg1, _] => Err(format!(
-                    "Type mismatch: expected String or Null but was {}",
-                    arg1.name(),
-                )),
-                args => Err(format!(
-                    "Received {} arguments to function 'string.matchRegEx', expected at least 2",
-                    args.len()
-                )),
+                    Ok(Value::List(all_matches))
+                }
+                Err(e) => Err(format!("Invalid regex, {e}")),
             },
-            _ => unreachable!(),
+            [Value::Null, _] | [_, Value::Null] => Ok(Value::List(vec![])),
+            [Value::String(_), arg2] => Err(format!(
+                "Type mismatch: expected String or Null but was {}",
+                arg2.name(),
+            )),
+            [arg1, _] => Err(format!(
+                "Type mismatch: expected String or Null but was {}",
+                arg1.name(),
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'string.matchRegEx', expected at least 2",
+                args.len()
+            )),
         }
     }
 
     fn string_replace_reg_ex(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [
-                    Value::String(text),
-                    Value::String(pattern),
-                    Value::String(replacement),
-                ] => match regex::Regex::new(pattern) {
-                    Ok(re) => {
-                        let replaced_text = re.replace_all(text, replacement).to_string();
-                        Ok(Value::String(replaced_text))
-                    }
-                    Err(e) => Err(format!("Invalid regex, {e}")),
-                },
-                [Value::Null, _, _] | [_, Value::Null, _] | [_, _, Value::Null] => Ok(Value::Null),
-                [Value::String(_), arg2, Value::String(_)] => Err(format!(
-                    "Type mismatch: expected String or Null but was {}",
-                    arg2.name(),
-                )),
-                [Value::String(_), Value::String(_), arg3] => Err(format!(
-                    "Type mismatch: expected String or Null but was {}",
-                    arg3.name(),
-                )),
-                [arg1, _, _] => Err(format!(
-                    "Type mismatch: expected String or Null but was {}",
-                    arg1.name(),
-                )),
-                args => Err(format!(
-                    "Received {} arguments to function 'string.replaceRegEx', expected at least 3",
-                    args.len()
-                )),
+        match args.as_slice() {
+            [
+                Value::String(text),
+                Value::String(pattern),
+                Value::String(replacement),
+            ] => match regex::Regex::new(pattern) {
+                Ok(re) => {
+                    let replaced_text = re.replace_all(text, replacement).to_string();
+                    Ok(Value::String(replaced_text))
+                }
+                Err(e) => Err(format!("Invalid regex, {e}")),
             },
-            _ => unreachable!(),
+            [Value::Null, _, _] | [_, Value::Null, _] | [_, _, Value::Null] => Ok(Value::Null),
+            [Value::String(_), arg2, Value::String(_)] => Err(format!(
+                "Type mismatch: expected String or Null but was {}",
+                arg2.name(),
+            )),
+            [Value::String(_), Value::String(_), arg3] => Err(format!(
+                "Type mismatch: expected String or Null but was {}",
+                arg3.name(),
+            )),
+            [arg1, _, _] => Err(format!(
+                "Type mismatch: expected String or Null but was {}",
+                arg1.name(),
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'string.replaceRegEx', expected at least 3",
+                args.len()
+            )),
+        }
+    }
+
+    fn abs(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Int(n.abs())),
+            [Value::Float(f)] => Ok(Value::Float(f.abs())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'abs', expected at most 1",
+                args.len()
+            )),
+        }
+    }
+
+    fn ceil(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Int(*n)),
+            [Value::Float(f)] => Ok(Value::Float(f.ceil())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'ceil', expected at most 1",
+                args.len()
+            )),
+        }
+    }
+
+    fn e(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [] => Ok(Value::Float(std::f64::consts::E)),
+            args => Err(format!(
+                "Received {} arguments to function 'e', expected at most 0",
+                args.len()
+            )),
+        }
+    }
+
+    fn exp(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Float((*n as f64).exp())),
+            [Value::Float(f)] => Ok(Value::Float(f.exp())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'exp', expected at most 1",
+                args.len()
+            )),
+        }
+    }
+
+    fn floor(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Int(*n)),
+            [Value::Float(f)] => Ok(Value::Float(f.floor())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'floor', expected at most 1",
+                args.len()
+            )),
+        }
+    }
+
+    fn log(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Float((*n as f64).ln())),
+            [Value::Float(f)] => Ok(Value::Float(f.ln())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'log', expected at most 1",
+                args.len()
+            )),
+        }
+    }
+
+    fn log10(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Float((*n as f64).log10())),
+            [Value::Float(f)] => Ok(Value::Float(f.log10())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'log10', expected at most 1",
+                args.len()
+            )),
+        }
+    }
+    fn pow(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(i1), Value::Int(i2)] => Ok(Value::Float((*i1 as f64).powi(*i2 as i32))),
+            [Value::Float(f1), Value::Float(f2)] => Ok(Value::Float(f1.powf(*f2))),
+            [Value::Int(i1), Value::Float(f1)] => Ok(Value::Float((*i1 as f64).powf(*f1))),
+            [Value::Float(f1), Value::Int(i1)] => Ok(Value::Float(f1.powi(*i1 as i32))),
+            [Value::Null, _] | [_, Value::Null] => Ok(Value::Null),
+            [v, Value::Int(_)] | [v, Value::Float(_)] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            [Value::Int(_), v] | [Value::Float(_), v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'pow', expected at least 2",
+                args.len()
+            )),
+        }
+    }
+
+    fn rand(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [] => {
+                let mut rng = rand::rng();
+                Ok(Value::Float(rng.random_range(0.0..1.0)))
path: graph/src/runtime.rs
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**`rand()` implementation will not compile – wrong API calls**

`rand::rng()` and `random_range` don’t exist in the current `rand 0.9` API.  
Use `thread_rng().gen_range()`.

```diff
-                let mut rng = rand::rng();
-                Ok(Value::Float(rng.random_range(0.0..1.0)))
+                let mut rng = thread_rng();
+                Ok(Value::Float(rng.gen_range(0.0..1.0)))
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
            [] => {
                let mut rng = thread_rng();
                Ok(Value::Float(rng.gen_range(0.0..1.0)))
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-29T17:23:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -691,106 +633,349 @@
                 .collect()
         }
 
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::List(vec), Value::String(s)] => {
-                    let result = to_string_vec(vec);
-                    result.map(|strings| Value::String(strings.join(s)))
-                }
-                [Value::List(vec)] => {
-                    let result = to_string_vec(vec);
-                    result.map(|strings| Value::String(strings.join("")))
-                }
-                [Value::Null, _] => Ok(Value::Null),
-                [arg1, _arg2] => Err(format!(
-                    "Type mismatch: expected List or Null but was {}",
-                    arg1.name()
-                )),
-                args => Err(format!(
-                    "Received {} arguments to function 'string.join', expected at most 2",
-                    args.len()
-                )),
-            },
-            _ => unreachable!(),
+        match args.as_slice() {
+            [Value::List(vec), Value::String(s)] => {
+                let result = to_string_vec(vec);
+                result.map(|strings| Value::String(strings.join(s)))
+            }
+            [Value::List(vec)] => {
+                let result = to_string_vec(vec);
+                result.map(|strings| Value::String(strings.join("")))
+            }
+            [Value::Null, _] => Ok(Value::Null),
+            [arg1, _arg2] => Err(format!(
+                "Type mismatch: expected List or Null but was {}",
+                arg1.name()
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'string.join', expected at most 2",
+                args.len()
+            )),
         }
     }
 
     fn string_match_reg_ex(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [Value::String(text), Value::String(pattern)] => match regex::Regex::new(pattern) {
-                    Ok(re) => {
-                        let mut all_matches = Vec::new();
-                        for caps in re.captures_iter(text) {
-                            for i in 0..caps.len() {
-                                if let Some(m) = caps.get(i) {
-                                    all_matches.push(Value::String(m.as_str().to_string()));
-                                }
+        match args.as_slice() {
+            [Value::String(text), Value::String(pattern)] => match regex::Regex::new(pattern) {
+                Ok(re) => {
+                    let mut all_matches = Vec::new();
+                    for caps in re.captures_iter(text) {
+                        for i in 0..caps.len() {
+                            if let Some(m) = caps.get(i) {
+                                all_matches.push(Value::String(m.as_str().to_string()));
                             }
                         }
-                        Ok(Value::List(all_matches))
                     }
-                    Err(e) => Err(format!("Invalid regex, {e}")),
-                },
-                [Value::Null, _] | [_, Value::Null] => Ok(Value::List(vec![])),
-                [Value::String(_), arg2] => Err(format!(
-                    "Type mismatch: expected String or Null but was {}",
-                    arg2.name(),
-                )),
-                [arg1, _] => Err(format!(
-                    "Type mismatch: expected String or Null but was {}",
-                    arg1.name(),
-                )),
-                args => Err(format!(
-                    "Received {} arguments to function 'string.matchRegEx', expected at least 2",
-                    args.len()
-                )),
+                    Ok(Value::List(all_matches))
+                }
+                Err(e) => Err(format!("Invalid regex, {e}")),
             },
-            _ => unreachable!(),
+            [Value::Null, _] | [_, Value::Null] => Ok(Value::List(vec![])),
+            [Value::String(_), arg2] => Err(format!(
+                "Type mismatch: expected String or Null but was {}",
+                arg2.name(),
+            )),
+            [arg1, _] => Err(format!(
+                "Type mismatch: expected String or Null but was {}",
+                arg1.name(),
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'string.matchRegEx', expected at least 2",
+                args.len()
+            )),
         }
     }
 
     fn string_replace_reg_ex(
         _: &Graph,
         _: &mut Self,
-        args: Value,
+        args: Vec<Value>,
     ) -> Result<Value, String> {
-        match args {
-            Value::List(arr) => match arr.as_slice() {
-                [
-                    Value::String(text),
-                    Value::String(pattern),
-                    Value::String(replacement),
-                ] => match regex::Regex::new(pattern) {
-                    Ok(re) => {
-                        let replaced_text = re.replace_all(text, replacement).to_string();
-                        Ok(Value::String(replaced_text))
-                    }
-                    Err(e) => Err(format!("Invalid regex, {e}")),
-                },
-                [Value::Null, _, _] | [_, Value::Null, _] | [_, _, Value::Null] => Ok(Value::Null),
-                [Value::String(_), arg2, Value::String(_)] => Err(format!(
-                    "Type mismatch: expected String or Null but was {}",
-                    arg2.name(),
-                )),
-                [Value::String(_), Value::String(_), arg3] => Err(format!(
-                    "Type mismatch: expected String or Null but was {}",
-                    arg3.name(),
-                )),
-                [arg1, _, _] => Err(format!(
-                    "Type mismatch: expected String or Null but was {}",
-                    arg1.name(),
-                )),
-                args => Err(format!(
-                    "Received {} arguments to function 'string.replaceRegEx', expected at least 3",
-                    args.len()
-                )),
+        match args.as_slice() {
+            [
+                Value::String(text),
+                Value::String(pattern),
+                Value::String(replacement),
+            ] => match regex::Regex::new(pattern) {
+                Ok(re) => {
+                    let replaced_text = re.replace_all(text, replacement).to_string();
+                    Ok(Value::String(replaced_text))
+                }
+                Err(e) => Err(format!("Invalid regex, {e}")),
             },
-            _ => unreachable!(),
+            [Value::Null, _, _] | [_, Value::Null, _] | [_, _, Value::Null] => Ok(Value::Null),
+            [Value::String(_), arg2, Value::String(_)] => Err(format!(
+                "Type mismatch: expected String or Null but was {}",
+                arg2.name(),
+            )),
+            [Value::String(_), Value::String(_), arg3] => Err(format!(
+                "Type mismatch: expected String or Null but was {}",
+                arg3.name(),
+            )),
+            [arg1, _, _] => Err(format!(
+                "Type mismatch: expected String or Null but was {}",
+                arg1.name(),
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'string.replaceRegEx', expected at least 3",
+                args.len()
+            )),
+        }
+    }
+
+    fn abs(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Int(n.abs())),
+            [Value::Float(f)] => Ok(Value::Float(f.abs())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'abs', expected at most 1",
+                args.len()
+            )),
+        }
+    }
+
+    fn ceil(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Int(*n)),
+            [Value::Float(f)] => Ok(Value::Float(f.ceil())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'ceil', expected at most 1",
+                args.len()
+            )),
+        }
+    }
+
+    fn e(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [] => Ok(Value::Float(std::f64::consts::E)),
+            args => Err(format!(
+                "Received {} arguments to function 'e', expected at most 0",
+                args.len()
+            )),
+        }
+    }
+
+    fn exp(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Float((*n as f64).exp())),
+            [Value::Float(f)] => Ok(Value::Float(f.exp())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'exp', expected at most 1",
+                args.len()
+            )),
+        }
+    }
+
+    fn floor(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Int(*n)),
+            [Value::Float(f)] => Ok(Value::Float(f.floor())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'floor', expected at most 1",
+                args.len()
+            )),
+        }
+    }
+
+    fn log(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Float((*n as f64).ln())),
+            [Value::Float(f)] => Ok(Value::Float(f.ln())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'log', expected at most 1",
+                args.len()
+            )),
+        }
+    }
+
+    fn log10(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Float((*n as f64).log10())),
+            [Value::Float(f)] => Ok(Value::Float(f.log10())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'log10', expected at most 1",
+                args.len()
+            )),
+        }
+    }
+    fn pow(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(i1), Value::Int(i2)] => Ok(Value::Float((*i1 as f64).powi(*i2 as i32))),
+            [Value::Float(f1), Value::Float(f2)] => Ok(Value::Float(f1.powf(*f2))),
+            [Value::Int(i1), Value::Float(f1)] => Ok(Value::Float((*i1 as f64).powf(*f1))),
+            [Value::Float(f1), Value::Int(i1)] => Ok(Value::Float(f1.powi(*i1 as i32))),
+            [Value::Null, _] | [_, Value::Null] => Ok(Value::Null),
+            [v, Value::Int(_)] | [v, Value::Float(_)] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            [Value::Int(_), v] | [Value::Float(_), v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'pow', expected at least 2",
+                args.len()
+            )),
+        }
+    }
+
+    fn rand(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [] => {
+                let mut rng = rand::rng();
+                Ok(Value::Float(rng.random_range(0.0..1.0)))
+            }
+            args => Err(format!(
+                "Received {} arguments to function 'rand', expected at most 0",
+                args.len()
+            )),
+        }
+    }
+
+    fn round(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Int(*n)),
+            [Value::Float(f)] => Ok(Value::Float(f.round())),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'round', expected at most 1",
+                args.len()
+            )),
+        }
+    }
+
+    fn sign(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => Ok(Value::Int(n.signum())),
+            [Value::Float(f)] => Ok(if *f == 0.0 {
+                Value::Int(0)
+            } else {
+                Value::Float(f.signum().round())
+            }),
+            [Value::Null] => Ok(Value::Null),
+            [v] => Err(format!(
+                "Type mismatch: expected Integer, Float, or Null but was {}",
+                v.name()
+            )),
+            args => Err(format!(
+                "Received {} arguments to function 'sign', expected at most 1",
+                args.len()
+            )),
+        }
+    }
+
+    fn sqrt(
+        _: &Graph,
+        _: &mut Self,
+        args: Vec<Value>,
+    ) -> Result<Value, String> {
+        match args.as_slice() {
+            [Value::Int(n)] => {
+                if *n < 0 {
+                    Ok(Value::Float(f64::NAN))
+                } else {
+                    Ok(Value::Float((*n as f64).sqrt()))
+                }
+            }
+            [Value::Float(f)] => {
+                if *f > 0f64 {
+                    Ok(Value::Float(f.sqrt()))
+                } else {
+                    Ok(Value::Float(f64::NAN))
path: graph/src/runtime.rs
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**`sqrt` of negative or zero floats – behaviour differs from Cypher**

`Cypher` returns `null` for negative inputs, whereas this implementation returns `NaN`.  
Also, `sqrt(0)` should be `0`, but the current `> 0f64` check classifies `0` as negative and returns `NaN`.

```diff
-            [Value::Float(f)] => {
-                if *f > 0f64 {
-                    Ok(Value::Float(f.sqrt()))
-                } else {
-                    Ok(Value::Float(f64::NAN))
-                }
+            [Value::Float(f)] => {
+                if *f < 0.0 {
+                    Ok(Value::Null)               // Cypher semantics
+                } else {
+                    Ok(Value::Float(f.sqrt()))    // works for 0.0 as well
+                }
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
            [Value::Float(f)] => {
-                if *f > 0f64 {
-                    Ok(Value::Float(f.sqrt()))
-                } else {
-                    Ok(Value::Float(f64::NAN))
-                }
+                if *f < 0.0 {
+                    Ok(Value::Null)               // Cypher semantics: sqrt(neg) → null
+                } else {
+                    Ok(Value::Float(f.sqrt()))    // sqrt(0) → 0.0 as desired
+                }
            }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-29T17:23:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -921,15 +935,29 @@
         }
     }
 
-    fn parse_exprs(&mut self) -> Result<Vec<QueryExprIR>, String> {
+    fn parse_expression_list(
+        &mut self,
+        expression_list_type: ExpressionListType,
+    ) -> Result<Vec<QueryExprIR>, String> {
         let mut exprs = Vec::new();
-        loop {
+        while !expression_list_type.is_end_token(self.lexer.current()) {
             exprs.push(self.parse_expr()?);
             match self.lexer.current() {
                 Token::Comma => self.lexer.next(),
-                _ => return Ok(exprs),
+                _ => break,
+            }
+        }
+
+        if let ExpressionListType::ZeroOrMoreClosedBy(token) = expression_list_type {
+            if self.lexer.current() == token {
+                self.lexer.next();
+            } else {
+                return Err(self
+                    .lexer
+                    .format_error(&format!("Unexpected token {token:?}")));
             }
         }
+        Ok(exprs)
     }
path: graph/src/cypher.rs
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

_⚠️ Potential issue_

**Add explicit validation for `OneOrMore` lists**

`parse_expression_list` allows an **empty** list when it’s invoked with `ExpressionListType::OneOrMore` (e.g. `DELETE` without arguments) – the grammar says this should be illegal.

A minimal fix that also removes the subtle move of `expression_list_type` is:

```diff
@@
-        if let ExpressionListType::ZeroOrMoreClosedBy(token) = expression_list_type {
-            if self.lexer.current() == token {
-                self.lexer.next();
-            } else {
-                return Err(self
-                    .lexer
-                    .format_error(&format!("Unexpected token {token:?}")));
-            }
-        }
+        match expression_list_type {
+            ExpressionListType::ZeroOrMoreClosedBy(token) => {
+                if self.lexer.current() == token {
+                    self.lexer.next();
+                } else {
+                    return Err(self
+                        .lexer
+                        .format_error(&format!("Unexpected token {token:?}")));
+                }
+            }
+            ExpressionListType::OneOrMore => {
+                if exprs.is_empty() {
+                    return Err(self
+                        .lexer
+                        .format_error("Expected at least one expression"));
+                }
+            }
+        }
```

This keeps the API semantics explicit, prevents silent acceptance of `DELETE`/`CALL (…)` with no payload, and avoids the move of `expression_list_type`.





<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    fn parse_expression_list(
        &mut self,
        expression_list_type: ExpressionListType,
    ) -> Result<Vec<QueryExprIR>, String> {
        let mut exprs = Vec::new();
        while !expression_list_type.is_end_token(self.lexer.current()) {
            exprs.push(self.parse_expr()?);
            match self.lexer.current() {
                Token::Comma => self.lexer.next(),
                _ => break,
            }
        }

        match expression_list_type {
            ExpressionListType::ZeroOrMoreClosedBy(token) => {
                if self.lexer.current() == token {
                    self.lexer.next();
                } else {
                    return Err(self
                        .lexer
                        .format_error(&format!("Unexpected token {token:?}")));
                }
            }
            ExpressionListType::OneOrMore => {
                if exprs.is_empty() {
                    return Err(self
                        .lexer
                        .format_error("Expected at least one expression"));
                }
            }
        }

        Ok(exprs)
    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-30T05:43:44Z
author_association: CONTRIBUTOR

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-04-29T08:34:29Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

This update introduces several new mathematical functions (`abs`, `ceil`, `e`, `exp`, `floor`, `log`, `log10`, `pow`, `rand`, `round`, `sign`, and `sqrt`) to the runtime, making them available for invocation with argument validation and error handling. The lexer and parser are refactored for improved digit consumption and function argument parsing, including an optimization for handling empty argument lists. Corresponding end-to-end tests are added to ensure correct functionality and error handling for the new functions. Additionally, the `syn` dependency in the macro crate is adjusted to use a lighter feature set, and the `rand` crate is added as a new dependency.

## Changes

| File(s)                   | Change Summary                                                                                              |
|---------------------------|-------------------------------------------------------------------------------------------------------------|
| falkordb-macro/Cargo.toml | Changed the `syn` dependency feature from `"full"` to `"parsing"`.                                          |
| graph/src/cypher.rs        | Added enum `ExpressionListType` to generalize expression list parsing with termination conditions; replaced `parse_exprs` with `parse_expression_list` using this enum; refactored digit consumption in `Lexer::lex_number` into helper method `consume_digits`; updated parser methods to use new parsing approach for function calls, delete clause, call clause, and list literals. |
| graph/src/runtime.rs       | Changed runtime function pointer types to accept `Vec<Value>` instead of single `Value`. Updated all runtime functions accordingly. Added twelve new mathematical functions (`abs`, `ceil`, `e`, `exp`, `floor`, `log`, `log10`, `pow`, `rand`, `round`, `sign`, `sqrt`) with argument validation and error handling. Updated calls in `ro_run` and `run` to pass argument vectors directly. |
| graph/Cargo.toml           | Added `rand` crate dependency version `0.9.1`.                                                             |
| tests/test_e2e.py          | Added end-to-end tests for new mathematical functions covering correct results, null handling, invalid argument types, and argument count errors. Modified `query` helper to allow equality assertion when results contain NaN. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant User
    participant Parser
    participant Runtime
    participant Functions

    User->>Parser: Call function (e.g., abs(-3))
    Parser->>Runtime: Evaluate function call
    Runtime->>Functions: Lookup and invoke (abs, ceil, e, exp, floor, log, log10, pow, rand, round, sign, sqrt)
    Functions-->>Runtime: Return result or error
    Runtime-->>Parser: Pass result/error
    Parser-->>User: Return final value or error
```

## Poem

> In the code garden, numbers leap and bound,  
> With abs and ceil, new math is found.  
> The constant e, exp’s soaring flight—  
> And floor and log bring math to light.  
> Pow joins the dance, a power play,  
> And rand and round brighten the day.  
> Sign and sqrt join the beat,  
> A lighter syn, a parser’s feat. 🐇✨

<!-- walkthrough_end -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 3b25372c8172911684353437307630106c2d26dc and 28438230da8944171a11fdf0c4787c36388b8287.

</details>

<details>
<summary>⛔ Files ignored due to path filters (1)</summary>

* `Cargo.lock` is excluded by `!**/*.lock`

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `tests/test_e2e.py` (3 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (1)</summary>

<details>
<summary>tests/test_e2e.py (4)</summary><blockquote>

<details>
<summary>tests/tck/test_tck.py (1)</summary>

* `query` (10-11)

</details>
<details>
<summary>graph/src/graph.rs (1)</summary>

* `query` (117-184)

</details>
<details>
<summary>graph/src/value.rs (1)</summary>

* `name` (90-102)

</details>
<details>
<summary>graph/src/runtime.rs (1)</summary>

* `e` (758-767)

</details>

</blockquote></details>

</details><details>
<summary>🪛 Ruff (0.8.2)</summary>

<details>
<summary>tests/test_e2e.py</summary>

1284-1284: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1291-1291: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1318-1318: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1325-1325: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1337-1337: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1361-1361: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1368-1368: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1395-1395: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1402-1402: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1426-1426: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1433-1433: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1457-1457: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1464-1464: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1506-1506: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1512-1512: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1519-1519: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1532-1532: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1559-1559: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1566-1566: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1601-1601: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1607-1607: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1634-1634: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

---

1641-1641: Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`

Replace `assert False`

(B011)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: test
* GitHub Check: coverage

</details>

<details>
<summary>🔇 Additional comments (1)</summary><blockquote>

<details>
<summary>tests/test_e2e.py (1)</summary>

`56-62`: **Well-implemented comparison logic for NaN values.**

The updated query helper now correctly handles NaN equality by using `math.isnan()`, which is necessary since NaN values are not equal to themselves in standard comparisons. This is crucial for testing mathematical functions like `log` and `sqrt` that return NaN for certain inputs.

</details>

</blockquote></details>

</details>
<!-- internal state start -->


<!-- DwQgtGAEAqAWCWBnSTIEMB26CuAXA9mAOYCmGJATmriQCaQDG+Ats2bgFyQAOFk+AIwBWJBrngA3EsgEBPRvlqU0AgfFwA6NPEgQAfACgjoCEejqANiS4rEAGkYl4FhyVcAPbg4Bm8d5ABiAFYABgMAOWxmAUouIIBmAwBVRFjIATQqAGsBI31jcCgyenxvHAJiMmUaeiZWdi5efmFRcSkZeSYlKlV1LR18kyg4VFRMcsJScioahXqMTkgqAHdIRCjmTPk5BW6VNU1tXTBDAtMDbzQLLPwKWgEwTYYKfAB6AGFMonwNAmYLDgGABEIIMAQCkAAggBJSrTah0NYbLb8MoMWCYUiIMywEiQJTcYpkBjyfBYXC4yAAA0QsgwVMYMzx8HJlKpl2ut3ujzQz3wDM+FG+vxYFkgviskGWaGQ6MxiJ2FBI3AsvJZREgFLx3hI1GwSvFqo13hezGpQO82AsFiBDII5u4mUQ6ttGhgCGQzEU8F80k1lLIKis9B1eoNqVwqP9eJpdIZzwR4tN0bmvBIuIwzqk5st1tt4t1uH1ePtaEgXoNFngzHUiKpQMdFGdGCI+dDRaVDm4+BoC3gVws8iVtGwDHVKcQTEJUctGDE8DJV3U8jQEm0qoEkpNLGptPpUvUsHweHQFhoFHHWsgUibC6wGCiMQoGiMRnBULP1TvyHtV6UDFVGZvyjEhPFuWZbh4bBN3gBhIHYdR4GkIxwjJEgXxBIE8nOIgqG4WBXkQCgGFeEl8MoDQm0BTCwQhGE4WqRF1lYFFSkYDEW2Qgw4DxOVOOQFlcBeEcGDxMtyFWMgompABRTwlUQZ0yQAGSQXBoFkQkGWWQ9r0yfsFmQKkAHlyGMigAFlbhIBlMHoKkAC1KHwcyrKVd4LHwVJaAAIVkAAKaB8CyMgAEo7XwSApmUKsAC88UbZsNTY0C00Uu9ICrRBcGQHSKXxH0dSVBZNUoGsMGoDKmAwWhELJRA3R4+CHzNFkAOwJRkDLNgKUUakkAAfWKAaCBC/d7XRUQshQMorwYfVisjUayDWeAiAqiwfwDGqoyvLLNBxBKnUocsSF6+zEpIIb5MQBlUCVFVeQVFdy2sw1QPgTcY0u660qUjABv2u0MSWtAQq6rAqTkv671U7KNK09AhSidhGo9U7zp4Y7kFShT/uQVJGwRegdjqTZkGwPsxSvYpNWClb7t1Sb6H8n10G4FVYKDEhQocarmMvSkAK8y96awNnUtaOgHEgpUOwwcdxkoF4+DZubPKSumxpQT0kCSl8DAABWOvgeqPWgtuoHglQkBdsEQQcsabRFcekf7MrU5BINSABHbBiT9fyqR+hgBwGgC0HtmyHGD46BqUKwaHD1Uo6pGOft4astl+igGW8SDZ3nMlGAHCH6H2j3zyuRBQqRvFsG4WhibpyAo+pH7XfSslAbU7TdLQDmXkzxMofkt3YbUhGbL0i9MByhxnWYTnvFkRWdspn1V5bFNEvHTyiFg8VIK1VIFEzITRxyg3oVZPErHcSgHD/Nb1DAfmoj3/B8G4ATIfvgaWpPlsgaJUlwxDWXoIJSK4kSCrFxBYQkpszrm2pO/Ng8cX45WBlbNAtA1xzj9HNDEVAxAnVrDMSCywECSlqgfHKdcj6U1oA4BuTdxDbysC2fKdl0DpC/lYcY3gjQoBqlzdhGpaHqFypQXi9UUa0DRqgeBiCdat28kfPgAgeywBETQUgfAeEml5OIRcYpGz0LYoAygDUUKRW0SdPiWIW7VSEvgMUQj8CrEgsrSCHFaBVm3pkZkCxhKjgVCQWQZJ6AnzxKA4xtx1Rl1bgrXwocTGZgNm+Oin4gL1Rbn+UQgFKp5JSmBCgEE+DcGglWOCCFxBcSgDJFq6BaBKFoFwUeMMVKT00tPPKOi1yz0MtSUyJBXLWVsjtRyzlxnuQ1nQPygUxbhREdSXCA9YAcA4GRXEucDBQAssgvquC2kdO8OLRAQ0aojTFv5AAZKkCw3g+YLXYDcsaXAgpjVricPhbi7qQ2rCqSA0M8YT3hr0qk+zICHMxicugZysBoKupInK/k5RUUgHc5gJ5DYkBIFkbmwB3jEMQHoBwnCuDYpPPbeA8U+ZyPQRixAVKcWRi0W4lZLJ+pLwsMAAA5GgPQkBlKgUoAKoVUKDlHPoM6daYZeIcVIO06k5ynapBzoge5bK1gkCeT84VAAlaQVpcDAAAGqiGAAARX9hQWQoLoSGvJZAAAykJdUegGSACTCVVWAO5jy7gDfa2qTyPOefBQN/0e7ZRGr0rgoLx7dIhYSA1kBjXrDPBaq1trKAOvkk6l17qLwti9asqkQK+WCuFcbZ2FAJVeuhbC82FNG7N3tG3WOzsc5JuDb3ER2VdQlDKF2jVuNbqAkgLoP16qrqh2tMnSOqRQ2RnDWmjNpqbV2tkE6hwxbPVQqnVAdk/q44JzOnOlOy7qWrr1d4ddJqs25vtbut1HrS2HunSe2dA1M6bHtTnFdur9W6CNY+s1z7828Fffuj9kB/KF3SSIiQ+A0kZR4RXKsVcxSh1SDXYEoJ9k4TwgRIiJEKCU3EGwSiLKCNYXfPRaKTJZXIntVGRxXEmoUb7GwcUlMi7+vwIJE6uBelGWNbggAYvuHhVIADqF4aDSeAYq+U0ToEMFEtwSMVJLUMAtVcf2ZaWSDtwVGMsSVJS6cMzZN0kJrRLEo9WbU/H0nIDTLbY8DsVyaeVOI3hlmYzmps8AogKMSr+XttgAcL1rMWH9lsuGuAqS1yCa3NtsxSy+e07w3TVrgvxZIGW2qSoxCDgcEqL0ttt5XnIIiDtGBlh4V4RXEz8AlApkQ3eRRXVvA6jEF1BzSozM8Ka7WPjc43MiParVbeVJniFiuhgRQ0dqTnqTnU2QadUHDaTkqVUbmEDcG2/N3bS2VsDXISd8g7hcAAJWyd3g39KCiZOxuPVt0Y5rkKzcy7CwSD6JO86eKJ3cS4LezKZLMdcDrhOzbaxq2aTQWyiWogQPOZQ93O+ogv3PLLEoED7Hv2G6IMJ6jgaD1VSiTJ+qQGJBvCY5pETs8F5mA05bBTtasBGco9p0IIT9IY68455sXA6IKcA+uuznHlOnoS5x6BbbPDhMUA2hNgTyAqwhX6v91XVwBrZUyDlAa/STsq42lci2JvDxm91xblx2hMxK6meb/XSpSDuAGqLyat00ayJCW4w0niB3tZLLiU+XW8moEXsvJCJN5AldaI7R0uBzxYG9wgbexcrx5f0wVozDIHawVidQXZ/pxjFxgYO+y+frAcCS1SA2kJIDKJOpHyGXxLnA6uj43Oqj4XqbWDDmqmRarxXghQFWp1FJoCcfnVWc5bilcjF8cLkYmCUZsdxfHFhswSXLKXkgouubuNc8BNLA/8lsmG7QAa7fboH+4B02wJ3RLOBO4j1KJ2PG3De/gNHMc+8AAjCEI9p4nDnZHDseDVEDmtILugFMogD7OUo3iCryDoryFpvQmWLngZoVmWjwnLPqJmLlhulmrXnutjl6n7vIGQPPqJEPheGIEjGFmwCVBviVDwqJtON9u1sUhgBVmdMQeOJ1M8PANppIHiL3l7OnkgBnm6JEGwEwerlNpgX5rogDo/EHtQDLHwA+A5t9v7PYEsEIarorIPN/LPDQJAC1JQIfApKal7JUkPLPpVNvPoZtH7tSNPO3pqGDH6MtiwWvkkkQarltP7obiVOhO6DGFQDASoRlDDuDDYdAsjGwdgTtKESQWWHEbQDuB4lbNygANohB2BAG1y0pza5FbKq5ED+QrKya5EsAU7yj+QhAaDtEaBAEdHhReHBzgEJHFzrAczgS/x6InSGKeRWwZB4YIH0CpRoSGSCHyyKzaGRgOFnj8B6FWhihsyYArhpHsCqIeF9Fyr7i+FZHhGrTrTSRsRXgshVKRjCb6JbFrHLHCHbzPEnQhAaKQDxQvBrEiKPGnHIHJaDFYCXGQDhBoDhC/HkBECVTZhfFNivHLYYBgDdjOhtDahTHzz8BagUA6SnyQlXhIHRYgJfwr5dRrEGyfDWg/iRQ35zFSiKYuaTbATcpUgvAU6UyTL2TcYqbpZsL1aRSOiKQpir7pHXitCQSJ5lbyAmY0BmZsRNYDzcDjjqCrI4G16Ja9wGyoT4ll77yHzeKT6+J2QBIagcbSIGiCShKiQKKvi0QfhVxTa/iUj/hFJTalLdjlKIiQRVIwS1J9j1LYjQokpqaai9Knj9jiZDrKZJg7gnr3IADiJGDgN66aTmbADgteD6maZqFBb6qOZa9oyZdyaZGyGZOqhq2ZbgkAemeBRm+Zm6RZsGRAxmkM6y+EhExErw3GVG6ETYUqkAEZnE0S0ZS4Mo1ICmtYCZ24Zo5ZOqlZ+E1ZJ4tZPG9ZeZoG6a4GTZ9Z7ZpZkUS5J4K5sAa5kYG5g5uZ+WNmegLZ5BNmlBJZAKayJGvZ5GdZNGI5SQGWTEcBCq5mQ2dZ4JyA7uakMikCkMN+d+Z+9UfJ1IY2Sc9+EU6A2WOmjZtenZpmw61IteVIk6X6aqC2CI92Sg/kRArKp56Zjmm5VFl5dZDgneXAmFd5D5hZT5xZB6BgR6M662PeIZAUlFWKy5NFA5zm9FWZm5TFQoLKDZt5+B7F+5z53FvF36JFe2eq/BiAR2FFklZ5FWdZklV5zmMlRAclrFilO5ZBHFhWKlH6PFRFSKZ2ZFV05CelWKBltFg5xljFLBFlClzZ1le5bZVBn6x6aqN2d2y25FwlFZYlRlIl65flzF8leebFwVBZylXFDlalaqT2iComHl8VVZ3lElSVDF0l/lLFgVRWSloVL5jlEVWA72m0xVXl4lbAvlVVqVllQVvyNl2Vh54VM6hhV0BAf24xFA7VCVdFFVUl151VaV+595mVrZnFw1TVM63eM1pVnV1g81JlOZS1fVdVa1j5dlOVHZI136YOtAu1q5ZVXVh1KVslNV6VVlA1IVG1YVW136qo2UD155T1B1mZR19ZvVtVq1X1WVDVqlTlfhzgQNhlc1YNr15l71K19VP1jVeVEJJAN4y6cVHViVaNPVb1y1WF2Nl1m1eNSIAgwudRxNs1PlL15NGNlNGVMN61NNv1dNiAGOyNIN3Vi1kNH1/VYGsNON8NzVjBtOE1eOlAQt+1ItplJ1UN1N/s9l11f1aqjNxOHMStzNe1pNNZ6NAV4tZ13NF1WtV1ja/NROsuokytptyV7NFtWN51tltttNCN+tVgDOLtqNZt7tmNVNXtQ1fNftzOHqzAQdrNZNotFNp10NktPNPtUdst+tF4RA3O8d5VidatYtnt1t3tB5md21RO/OLI+dz1hdx1xd4dpdkduN0d5OGe8u10tdoNIdSdHNKdmt5drdWdjtyoVOV07uXdxtj1KtbNfdHtTdadNtQ9MtM6ruFgBuMO5Sly/S3dqtDdydGtEdcNuVCN69luO9h4e9c9Rdh9ltqdu5UtvNw9a9du+uDuJm199dENd9JdS9Zd2t9tZ9b9G97uoEXu1APuX9vdt9/dR9zdJ9OtdN9wgMKgH20Dbti1A0jdXN/9Ldq936KD3B0gGDlVWDODn1eDiDQDstKDBVL2SEWq09wNs939Dg2Dv9i9j96dK9DlUAkIrSiI++TJ9+B4+UZxgF5ZXlbDnNlD3Dy9gDBFutWAtgpDC1sDC9uD8jADdtN1xFTgFgaj4NZlmjcjg11DejWAJARj5tYdWj5j0tp9stqUNjodsjEt2j+DTjM6P+01zDKNCdMDB9cD99g9ijyjmU/+rj89djZj31z9BDaqwBIQ0TGjsTHjDjCT3j363YywqTwTpjGT8TGdL936uR+TP9ITf9njFjETLwTCFTJj6TVtVDjjSDftcBjT6toTx9bTND21oJXTFDRTT9JT3FUAv5wptQpcLcTJo2rJoF5a3JApzJXJvJLcYpRkKdDIcpuAjsipQ6UYqpHMGpkMOp9eepdG2EYARgNA2UiArwdzd2JAAATOhNwLINRKCAxrCExs3MxP+qSGiEqpxmyKLrAAyF6COJKNKAJEvOBHQH0X7HmgyK3nwL4bC69LVL6IPnUI2GHrEeBgbmdAyCqQs4QYc8ixeH6HqkfuwGAESRDdaJ4uOCQH7EuKJhszKAJGUFovlEwJPtIN2KItvLS+kV1AaGy9FmKJBHyxgQaNCbCZFprFSOCxoEgBVPSKFHZplF8HiOsONilDVGABULTE87lNOZfvPgflqMfvOqBc/gza/gYx/h/p4N/p5L/oAf/n/kQCAWAcsBATATHPU8G7uHAc7vZEgSgW6DJOgaVNlNKReL6LKEvq0CYfLHpIVsgNa7wVBY8b/DNuOJiYhFIA4PCYifWf8fgExTtB4SXHhjQaeIgJFE8+Xk8RgHm0EVKcQ8gP5D5PwrqAITCgPA4ElrXFQEgCWNGTWIgBnhPirLlLpJLKQvQGwDPliHZq0nVBtOVgm/QtVL4BQGaBSFbPOpadGBHnBSQf0ggdNmm8wVYnwGxJKewD+Dnfol1BYcPNYa++wdAZGNIW6K6oSGOFcA236Glk84iNa1SPvAhXB//v6/BuhEQBoBSlEyEBO6YSQRW9iSIr4ArKJhh8lGUHh5ITYY+NYhm8QcgIq9qzEdSLkXnNe/u0mz6IwymMeLgI8aov0sUe0aUZAN0Vh14fvua0fMy6sDTO4GpMW9QGnlGFS1vBqH+NQCoDKGJDtNywwzVkLA+7gOQOKXcZSBsbepGMfAGGaUghu+hE6QxjktpVfniJ6ZkE5z6QiyUJUtUofHUow3kFCIIyGKx1SE89gwzfUa+aF9IDlI8zF0NG8xoB8yOQI20uCdSGF2/oY1ypDOa3F7Gq8+81ttCqlzByF2F9YzlxlzFw8xV4l8lyV0F+l9FwV54JF+Wnl3V0Vyl0174S13dr4+15yZ1/F4V0l8V/w71+V/F/vEN7lzV/l88/VxN4F2l312F8k3N9V/c4twl91412t9N7Grk1t/17V6N8tz14d+ycXP1y0TVKdyNwV5dwd2Vzd/N7GqG/dVV2d7t2Nw15N9dwJtt3dmcY9wt11+N1d298D3d9G7gODzt5Dw1zRERjcwYN2QRIKMKH8ACFcz8wxMxkiCxGxmxNaYdPiMqESHOPIK1rfG+Rsh8F8D8Lj3nM4HiJi6ws3DsCcqsfvgmNYQSNTySB0sx0m+7FSO0QAJxdGoEGn2J8DWlSgyIH4dbulHQMCEqkAYy4LqevEfTZQiFU81TEiMOZLOn2aunATq+U8Ry5IkEed+ledQRBnNTiChm2LkAYSEb5AGBDDNS4WRwVB/OzBkwNBLBoCrAAsoikwrY9AHD9DHCGD+9kzqCXZW42xIT4636G7lJJ9nBQCCMAActAQQAA7EXwwJcLyOXwACz05AE6hS+l8kAABsfWtAUvIQQQAgrfLzRf9Otf8Q+f/vogZfCQDpRfUvJAtfSgJAPfrftA8QQBtfVf5fIQ8QIQQBQQmmRf7f+KQQrfI/hQ+IZfUvO/bftfAgUvDA8Q3gIQIQtAZfQBQBLzaAK/8Q8QQQoQT/9/Lzj/oQMvvEDgiDAT+3gWvt4AYAhBx+oQGIGgCAECAy+QA1vrgmAGr8b+S/WfkEDQAz8u+N/YfqAIgCU9a+RfXkLXyAJ0A0A3gUgfECL5AEYgAgIILQG8B98SAUvNAEEBX7d8XmrfLfkAXiBH9CBUAHfmgGX6iQmY9wVfppggGt9W+QBVvkX1r5l9a+QQGfgIAYAoDGBUvZ/kEBebH8iB/fWvm81b4kBSBvIeQQwDL4kAt+m/eIGgHYFoAQgUvbwE3Bn4MApeq/EIDwJ+JCDGALzJuC8zL4b9vATAkIJAKAK0AQCTg/FBkDQCiDmBEAnfrQFX6XB2++gqAEgLL6YCIBRffwfEBeZBApeRfMvlQO35l8GA6g2vuQJeYkCv+RQlgUXxCC190hwnF5lX0/5D94gz/KXhkBv704BA3gDIK81r7d8q+ogeAQwEaFl9qBZQXwfECv5MDaAU/egfcCUDlCl+okIIEPxUGt9m+QQgQFfzQByCXmr/IIC0K8FoA3+kQioc/1GEhAFBJA2gE4I4GkCy+xw7/kPwiGQCQgAgFoSQE/5AFcEPfKXuwMKF994g2gqARANaSQDm+tfEwc3yYHf82+eIXwdYIr5F87BHg8/r3wGHeB4gAgWgSoGX6NCeBRfA4Y323799pBLQgkQUK6FtC6BZfF5lLxf4PCv+8wroZvzeGb8QCrfBgP4J4G0AQBJwP3if0MG0CXmm/JuFPyqFAFn+7/RvswJCAMAlBxQ2/q31oHkjchxQ/PmKKIGp87s7WS5Jn1gR0BLcSfIAA=== -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=FalkorDB/falkordb-rs-next-gen&utm_content=53):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: codecov[bot]
created_at: 2025-04-29T08:59:10Z
body: ## [Codecov](https://app.codecov.io/gh/FalkorDB/falkordb-rs-next-gen/pull/53?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=FalkorDB) Report
Attention: Patch coverage is `90.66667%` with `63 lines` in your changes missing coverage. Please review.
> Project coverage is 61.97%. Comparing base [(`40a9e56`)](https://app.codecov.io/gh/FalkorDB/falkordb-rs-next-gen/commit/40a9e56e5fb7f8cfd76328f538511cd0ebad71f7?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=FalkorDB) to head [(`1d77894`)](https://app.codecov.io/gh/FalkorDB/falkordb-rs-next-gen/commit/1d77894347ee9b9b56f23d979cfae3c19ad9d989?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=FalkorDB).
> Report is 18 commits behind head on main.

| [Files with missing lines](https://app.codecov.io/gh/FalkorDB/falkordb-rs-next-gen/pull/53?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=FalkorDB) | Patch % | Lines |
|---|---|---|
| [graph/src/runtime.rs](https://app.codecov.io/gh/FalkorDB/falkordb-rs-next-gen/pull/53?src=pr&el=tree&filepath=graph%2Fsrc%2Fruntime.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=FalkorDB#diff-Z3JhcGgvc3JjL3J1bnRpbWUucnM=) | 90.43% | [60 Missing :warning: ](https://app.codecov.io/gh/FalkorDB/falkordb-rs-next-gen/pull/53?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=FalkorDB) |
| [graph/src/cypher.rs](https://app.codecov.io/gh/FalkorDB/falkordb-rs-next-gen/pull/53?src=pr&el=tree&filepath=graph%2Fsrc%2Fcypher.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=FalkorDB#diff-Z3JhcGgvc3JjL2N5cGhlci5ycw==) | 93.75% | [3 Missing :warning: ](https://app.codecov.io/gh/FalkorDB/falkordb-rs-next-gen/pull/53?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=FalkorDB) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main      #53      +/-   ##
==========================================
- Coverage   67.94%   61.97%   -5.98%     
==========================================
  Files           8        8              
  Lines        4605     5378     +773     
==========================================
+ Hits         3129     3333     +204     
- Misses       1476     2045     +569     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/FalkorDB/falkordb-rs-next-gen/pull/53?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=FalkorDB).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=FalkorDB).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE