From 2f5a670b3a594a4e5997e6cf31bc78a1bed0e5e1 Mon Sep 17 00:00:00 2001 From: Jonas Breuer Date: Thu, 25 Feb 2021 20:00:23 +0100 Subject: [PATCH 01/14] Added Aerospike 5.6 Basic Expressions --- src/expressions/mod.rs | 620 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 614 insertions(+), 6 deletions(-) diff --git a/src/expressions/mod.rs b/src/expressions/mod.rs index 1bdd4135..ad3eecff 100644 --- a/src/expressions/mod.rs +++ b/src/expressions/mod.rs @@ -68,6 +68,31 @@ pub enum ExpOp { And = 16, Or = 17, Not = 18, + Xor = 19, + Add = 20, + Sub = 21, + Mul = 22, + Div = 23, + Pow = 24, + Log = 25, + Mod = 26, + Abs = 27, + Floor = 28, + Ceil = 29, + ToInt = 30, + ToFloat = 31, + IntAnd = 32, + IntOr = 33, + IntXor = 34, + IntNot = 35, + IntLshift = 36, + IntRshift = 37, + IntARshift = 38, + IntCount = 39, + IntLscan = 40, + IntRscan = 41, + Min = 50, + Max = 51, DigestModulo = 64, DeviceSize = 65, LastUpdate = 66, @@ -80,6 +105,9 @@ pub enum ExpOp { Key = 80, Bin = 81, BinType = 82, + Cond = 123, + Var = 124, + Let = 125, Quoted = 126, Call = 127, } @@ -112,7 +140,7 @@ pub struct FilterExpression { module: Option, /// Sub commands for the CmdExp operation exps: Option>, - + /// Optional Arguments (CDT) arguments: Option>, } @@ -144,10 +172,26 @@ impl FilterExpression { buf: &mut Option<&mut Buffer>, ) -> Result { let mut size = 0; - size += pack_array_begin(buf, exps.len() + 1)?; - size += pack_integer(buf, self.cmd.unwrap() as i64)?; - for exp in exps { - size += exp.pack(buf)?; + if let Some(val) = &self.val { + // DEF expression + size += pack_value(buf, val)?; + exps[0].pack(buf)?; + } else { + // Normal Expressions + match self.cmd.unwrap() { + ExpOp::Let => { + // Let wire format: LET , , , , ..., + let count = (exps.len() - 1) * 2 + 2; + size += pack_array_begin(buf, count)?; + } + _ => { + size += pack_array_begin(buf, exps.len() + 1)?; + } + } + size += pack_integer(buf, self.cmd.unwrap() as i64)?; + for exp in exps { + size += exp.pack(buf)?; + } } Ok(size) } @@ -828,4 +872,568 @@ pub fn le(left: FilterExpression, right: FilterExpression) -> FilterExpression { } } -// ---------------------------------------------- +/// Create "add" (+) operator that applies to a variable number of expressions. +/// Return sum of all FilterExpressions given. All arguments must resolve to the same type (integer or float). +/// Requires server version 5.6.0+. +/// ``` +/// use aerospike::expressions::{eq, num_add, int_bin, int_val}; +/// // a + b + c == 10 +/// eq(num_add(vec![int_bin("a".to_string()), int_bin("b".to_string()), int_bin("c".to_string())]), int_val(10)); +/// ``` +pub fn num_add(exps: Vec) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::Add), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(exps), + arguments: None, + } +} + +/// Create "subtract" (-) operator that applies to a variable number of expressions. +/// If only one FilterExpression is provided, return the negation of that argument. +/// Otherwise, return the sum of the 2nd to Nth FilterExpression subtracted from the 1st +/// FilterExpression. All FilterExpressions must resolve to the same type (integer or float). +/// Requires server version 5.6.0+. +/// ``` +/// use aerospike::expressions::{gt, num_sub, int_bin, int_val}; +/// // a - b - c > 10 +/// gt(num_sub(vec![int_bin("a".to_string()), int_bin("b".to_string()), int_bin("c".to_string())]), int_val(10)); +/// ``` +pub fn num_sub(exps: Vec) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::Sub), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(exps), + arguments: None, + } +} + +/// Create "multiply" (*) operator that applies to a variable number of expressions. +/// Return the product of all FilterExpressions. If only one FilterExpressions is supplied, return +/// that FilterExpressions. All FilterExpressions must resolve to the same type (integer or float). +/// Requires server version 5.6.0+. +/// ``` +/// use aerospike::expressions::{lt, num_mul, int_val, int_bin}; +/// // a * b * c < 100 +/// lt(num_mul(vec![int_bin("a".to_string()), int_bin("b".to_string()), int_bin("c".to_string())]), int_val(100)); +/// ``` +pub fn num_mul(exps: Vec) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::Mul), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(exps), + arguments: None, + } +} + +/// Create "divide" (/) operator that applies to a variable number of expressions. +/// If there is only one FilterExpressions, returns the reciprocal for that FilterExpressions. +/// Otherwise, return the first FilterExpressions divided by the product of the rest. +/// All FilterExpressions must resolve to the same type (integer or float). +/// Requires server version 5.6.0+. +/// ``` +/// use aerospike::expressions::{lt, int_val, int_bin, num_div}; +/// // a / b / c > 1 +/// lt(num_div(vec![int_bin("a".to_string()), int_bin("b".to_string()), int_bin("c".to_string())]), int_val(1)); +/// ``` +pub fn num_div(exps: Vec) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::Div), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(exps), + arguments: None, + } +} + +/// Create "power" operator that raises a "base" to the "exponent" power. +/// All arguments must resolve to floats. +/// Requires server version 5.6.0+. +/// ``` +/// // pow(a, 2.0) == 4.0 +/// use aerospike::expressions::{eq, num_pow, float_bin, float_val}; +/// eq(num_pow(float_bin("a".to_string()), float_val(2.0)), float_val(4.0)); +/// ``` +pub fn num_pow(base: FilterExpression, exponent: FilterExpression) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::Pow), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(vec![base, exponent]), + arguments: None, + } +} + +/// Create "log" operator for logarithm of "num" with base "base". +/// All arguments must resolve to floats. +/// Requires server version 5.6.0+. +/// ``` +/// // log(a, 2.0) == 4.0 +/// use aerospike::expressions::{eq, float_bin, float_val, num_log}; +/// eq(num_log(float_bin("a".to_string()), float_val(2.0)), float_val(4.0)); +/// ``` +pub fn num_log(num: FilterExpression, base: FilterExpression) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::Log), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(vec![num, base]), + arguments: None, + } +} + +/// Create "modulo" (%) operator that determines the remainder of "numerator" +/// divided by "denominator". All arguments must resolve to integers. +/// Requires server version 5.6.0+. +/// ``` +/// // a % 10 == 0 +/// use aerospike::expressions::{eq, num_mod, int_val, int_bin}; +/// eq(num_mod(int_bin("a".to_string()), int_val(10)), int_val(0)); +/// ``` +pub fn num_mod(numerator: FilterExpression, denominator: FilterExpression) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::Mod), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(vec![numerator, denominator]), + arguments: None, + } +} + +/// Create operator that returns absolute value of a number. +/// All arguments must resolve to integer or float. +/// Requires server version 5.6.0+. +/// ``` +/// // abs(a) == 1 +/// use aerospike::expressions::{eq, int_val, int_bin, num_abs}; +/// eq(num_abs(int_bin("a".to_string())), int_val(1)); +/// ``` +pub fn num_abs(value: FilterExpression) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::Abs), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(vec![value]), + arguments: None, + } +} + +/// Create expression that rounds a floating point number down to the closest integer value. +/// The return type is float. +// Requires server version 5.6.0+. +/// ``` +/// // floor(2.95) == 2.0 +/// use aerospike::expressions::{eq, num_floor, float_val}; +/// eq(num_floor(float_val(2.95)), float_val(2.0)); +/// ``` +pub fn num_floor(num: FilterExpression) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::Floor), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(vec![num]), + arguments: None, + } +} + +/// Create expression that rounds a floating point number up to the closest integer value. +/// The return type is float. +/// Requires server version 5.6.0+. +/// ``` +/// // ceil(2.15) == 3.0 +/// use aerospike::expressions::{float_val, num_ceil, ge}; +/// ge(num_ceil(float_val(2.15)), float_val(3.0)); +/// ``` +pub fn num_ceil(num: FilterExpression) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::Ceil), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(vec![num]), + arguments: None, + } +} + +/// Create expression that converts an integer to a float. +/// Requires server version 5.6.0+. +/// ``` +/// // int(2.5) == 2 +/// use aerospike::expressions::{float_val, eq, to_int, int_val}; +/// eq(to_int(float_val(2.5)), int_val(2)); +/// ``` +pub fn to_int(num: FilterExpression) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::ToInt), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(vec![num]), + arguments: None, + } +} + +/// Create expression that converts a float to an integer. +/// Requires server version 5.6.0+. +/// ``` +/// // float(2) == 2.0 +/// use aerospike::expressions::{float_val, eq, to_float, int_val}; +/// eq(to_float(int_val(2)), float_val(2.0)); +/// ``` +pub fn to_float(num: FilterExpression) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::ToFloat), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(vec![num]), + arguments: None, + } +} + +/// Create integer "and" (&) operator that is applied to two or more integers. +/// All arguments must resolve to integers. +/// Requires server version 5.6.0+. +/// ``` +/// // a & 0xff == 0x11 +/// use aerospike::expressions::{eq, int_val, int_and, int_bin}; +/// eq(int_and(vec![int_bin("a".to_string()), int_val(0xff)]), int_val(0x11)); +/// ``` +pub fn int_and(exps: Vec) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::IntAnd), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(exps), + arguments: None, + } +} + +/// Create integer "xor" (^) operator that is applied to two or more integers. +/// All arguments must resolve to integers. +/// Requires server version 5.6.0+. +/// ``` +/// // a ^ b == 16 +/// use aerospike::expressions::{eq, int_val, int_xor, int_bin}; +/// eq(int_xor(vec![int_bin("a".to_string()), int_bin("b".to_string())]), int_val(16)); +/// ``` +pub fn int_xor(exps: Vec) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::IntXor), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(exps), + arguments: None, + } +} + +/// Create integer "not" (~) operator. +/// Requires server version 5.6.0+. +/// ``` +/// // ~a == 7 +/// use aerospike::expressions::{eq, int_val, int_not, int_bin}; +/// eq(int_not(int_bin("a".to_string())), int_val(7)); +/// ``` +pub fn int_not(exp: FilterExpression) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::IntNot), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(vec![exp]), + arguments: None, + } +} + +/// Create integer "left shift" (<<) operator. +/// Requires server version 5.6.0+. +/// ``` +/// // a << 8 > 0xff +/// use aerospike::expressions::{int_val, int_bin, gt, int_lshift}; +/// gt(int_lshift(int_bin("a".to_string()), int_val(8)), int_val(0xff)); +/// ``` +pub fn int_lshift(value: FilterExpression, shift: FilterExpression) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::IntLshift), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(vec![value, shift]), + arguments: None, + } +} + +/// Create integer "logical right shift" (>>>) operator. +/// Requires server version 5.6.0+. +/// ``` +/// // a >> 8 > 0xff +/// use aerospike::expressions::{int_val, int_bin, gt, int_rshift}; +/// gt(int_rshift(int_bin("a".to_string()), int_val(8)), int_val(0xff)); +/// ``` +pub fn int_rshift(value: FilterExpression, shift: FilterExpression) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::IntRshift), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(vec![value, shift]), + arguments: None, + } +} + +/// Create integer "arithmetic right shift" (>>) operator. +/// The sign bit is preserved and not shifted. +/// Requires server version 5.6.0+. +/// ``` +/// // a >>> 8 > 0xff +/// use aerospike::expressions::{int_val, int_bin, gt, int_arshift}; +/// gt(int_arshift(int_bin("a".to_string()), int_val(8)), int_val(0xff)); +/// ``` +pub fn int_arshift(value: FilterExpression, shift: FilterExpression) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::IntARshift), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(vec![value, shift]), + arguments: None, + } +} + +/// Create expression that returns count of integer bits that are set to 1. +/// Requires server version 5.6.0+. +/// ``` +/// // count(a) == 4 +/// use aerospike::expressions::{int_val, int_bin, int_count, eq}; +/// eq(int_count(int_bin("a".to_string())), int_val(4)); +/// ``` +pub fn int_count(exp: FilterExpression) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::IntCount), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(vec![exp]), + arguments: None, + } +} + +/// Create expression that scans integer bits from left (most significant bit) to +/// right (least significant bit), looking for a search bit value. When the +/// search value is found, the index of that bit (where the most significant bit is +/// index 0) is returned. If "search" is true, the scan will search for the bit +/// value 1. If "search" is false it will search for bit value 0. +/// Requires server version 5.6.0+. +/// ``` +/// // lscan(a, true) == 4 +/// use aerospike::expressions::{int_val, int_bin, eq, int_lscan, bool_val}; +/// eq(int_lscan(int_bin("a".to_string()), bool_val(true)), int_val(4)); +/// ``` +pub fn int_lscan(value: FilterExpression, search: FilterExpression) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::IntLscan), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(vec![value, search]), + arguments: None, + } +} + +/// Create expression that scans integer bits from right (least significant bit) to +/// left (most significant bit), looking for a search bit value. When the +/// search value is found, the index of that bit (where the most significant bit is +/// index 0) is returned. If "search" is true, the scan will search for the bit +/// value 1. If "search" is false it will search for bit value 0. +/// Requires server version 5.6.0+. +/// ``` +/// // rscan(a, true) == 4 +/// use aerospike::expressions::{int_val, int_bin, eq, int_rscan, bool_val}; +/// eq(int_rscan(int_bin("a".to_string()), bool_val(true)), int_val(4)); +/// ``` +pub fn int_rscan(value: FilterExpression, search: FilterExpression) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::IntRscan), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(vec![value, search]), + arguments: None, + } +} + +/// Create expression that returns the minimum value in a variable number of expressions. +/// All arguments must be the same type (integer or float). +/// Requires server version 5.6.0+. +/// ``` +/// // min(a, b, c) > 0 +/// use aerospike::expressions::{int_val, int_bin, gt, min}; +/// gt(min(vec![int_bin("a".to_string()),int_bin("b".to_string()),int_bin("c".to_string())]), int_val(0)); +/// ``` +pub fn min(exps: Vec) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::Min), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(exps), + arguments: None, + } +} + +/// Create expression that returns the maximum value in a variable number of expressions. +/// All arguments must be the same type (integer or float). +/// Requires server version 5.6.0+. +/// ``` +/// // max(a, b, c) > 100 +/// use aerospike::expressions::{int_val, int_bin, gt, max}; +/// gt(max(vec![int_bin("a".to_string()),int_bin("b".to_string()),int_bin("c".to_string())]), int_val(100)); +/// ``` +pub fn max(exps: Vec) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::Max), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(exps), + arguments: None, + } +} + +//-------------------------------------------------- +// Variables +//-------------------------------------------------- + +/// Conditionally select an expression from a variable number of expression pairs +/// followed by default expression action. +/// Requires server version 5.6.0+. +/// ``` +/// // Args Format: bool exp1, action exp1, bool exp2, action exp2, ..., action-default +/// // Apply operator based on type. +/// +/// use aerospike::expressions::{cond, int_bin, eq, int_val, num_add, num_sub, num_mul}; +/// cond( +/// vec![ +/// eq(int_bin("type".to_string()), int_val(0)), num_add(vec![int_bin("val1".to_string()), int_bin("val2".to_string())]), +/// eq(int_bin("type".to_string()), int_val(1)), num_sub(vec![int_bin("val1".to_string()), int_bin("val2".to_string())]), +/// eq(int_bin("type".to_string()), int_val(2)), num_mul(vec![int_bin("val1".to_string()), int_bin("val2".to_string())]), +/// int_val(-1) +/// ] +/// ); +/// ``` +pub fn cond(exps: Vec) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::Cond), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(exps), + arguments: None, + } +} + +/// Define variables and expressions in scope. +/// Requires server version 5.6.0+. +/// ``` +/// // 5 < a < 10 +/// use aerospike::expressions::{exp_let, def, int_bin, and, lt, int_val, var}; +/// exp_let( +/// vec![ +/// def("x".to_string(), int_bin("a".to_string())), +/// and(vec![ +/// lt(int_val(5), var("x".to_string()),), +/// lt(var("x".to_string()), int_val(10)) +/// ]) +/// ] +/// ); +/// ``` +pub fn exp_let(exps: Vec) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::Let), + val: None, + bin: None, + flags: None, + module: None, + exps: Some(exps), + arguments: None, + } +} + +/// Assign variable to an expression that can be accessed later. +/// Requires server version 5.6.0+. +/// ``` +/// // 5 < a < 10 +/// use aerospike::expressions::{exp_let, def, int_bin, and, lt, int_val, var}; +/// exp_let( +/// vec![ +/// def("x".to_string(), int_bin("a".to_string())), +/// and(vec![ +/// lt(int_val(5), var("x".to_string()),), +/// lt(var("x".to_string()), int_val(10)) +/// ]) +/// ] +/// ); +/// ``` +pub fn def(name: String, value: FilterExpression) -> FilterExpression { + FilterExpression { + cmd: None, + val: Some(Value::from(name)), + bin: None, + flags: None, + module: None, + exps: Some(vec![value]), + arguments: None, + } +} + +/// Retrieve expression value from a variable. +/// Requires server version 5.6.0+. +pub fn var(name: String) -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::Var), + val: Some(Value::from(name)), + bin: None, + flags: None, + module: None, + exps: None, + arguments: None, + } +} From 86499d06329db345142451c13ea8278f65707dc3 Mon Sep 17 00:00:00 2001 From: Jonas Breuer Date: Thu, 25 Feb 2021 20:13:51 +0100 Subject: [PATCH 02/14] Added HLL Expressions --- src/expressions/hll.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/expressions/hll.rs b/src/expressions/hll.rs index 065ffded..0595c9a9 100644 --- a/src/expressions/hll.rs +++ b/src/expressions/hll.rs @@ -23,6 +23,7 @@ const MODULE: i64 = 2; #[doc(hidden)] pub enum HllExpOp { + Init = 0, Add = 1, Count = 50, Union = 51, @@ -33,6 +34,24 @@ pub enum HllExpOp { MayContain = 56, } +/// Create expression that creates a new HLL or resets an existing HLL. +pub fn init(policy: HLLPolicy, index_bit_count: FilterExpression, bin: FilterExpression) -> FilterExpression { + init_with_min_hash(policy, index_bit_count, int_val(-1), bin) +} + +/// Create expression that creates a new HLL or resets an existing HLL with minhash bits. +pub fn init_with_min_hash(policy: HLLPolicy, index_bit_count: FilterExpression, min_hash_count: FilterExpression, bin: FilterExpression) -> FilterExpression { + add_write( + bin, + vec![ + ExpressionArgument::Value(Value::from(HllExpOp::Init as i64)), + ExpressionArgument::FilterExpression(index_bit_count), + ExpressionArgument::FilterExpression(min_hash_count), + ExpressionArgument::Value(Value::from(policy.flags as i64)), + ], + ) +} + /// Create expression that adds list values to a HLL set and returns HLL set. /// The function assumes HLL bin already exists. /// ``` From 3550b945dcab10efdf1a6e1c1aee1d4bb669a13d Mon Sep 17 00:00:00 2001 From: Jonas Breuer Date: Thu, 25 Feb 2021 21:44:17 +0100 Subject: [PATCH 03/14] Added Exp Operations --- src/commands/buffer.rs | 6 ++- src/expressions/mod.rs | 1 - src/operations/exp.rs | 102 +++++++++++++++++++++++++++++++++++++++++ src/operations/mod.rs | 10 ++++ 4 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 src/operations/exp.rs diff --git a/src/commands/buffer.rs b/src/commands/buffer.rs index 4dc6bbd3..b5a54b6e 100644 --- a/src/commands/buffer.rs +++ b/src/commands/buffer.rs @@ -504,12 +504,16 @@ impl Buffer { | Operation { op: OperationType::HllRead, .. + } + | Operation { + op: OperationType::ExpRead, + .. } => read_attr |= INFO1_READ, _ => write_attr |= INFO2_WRITE, } let each_op = - matches!(operation.data, OperationData::CdtMapOp(_) | OperationData::CdtBitOp(_)); + matches!(operation.data, OperationData::CdtMapOp(_) | OperationData::CdtBitOp(_) | OperationData::HLLOp(_) | OperationData::EXPOp(_)); if policy.respond_per_each_op || each_op { write_attr |= INFO2_RESPOND_ALL_OPS; diff --git a/src/expressions/mod.rs b/src/expressions/mod.rs index ad3eecff..d4a40e24 100644 --- a/src/expressions/mod.rs +++ b/src/expressions/mod.rs @@ -20,7 +20,6 @@ pub mod hll; pub mod lists; pub mod maps; pub mod regex_flag; - use crate::commands::buffer::Buffer; use crate::errors::Result; use crate::msgpack::encoder::{pack_array_begin, pack_integer, pack_raw_string, pack_value}; diff --git a/src/operations/exp.rs b/src/operations/exp.rs new file mode 100644 index 00000000..a2549542 --- /dev/null +++ b/src/operations/exp.rs @@ -0,0 +1,102 @@ +use crate::expressions::FilterExpression; +use crate::operations::{Operation, OperationType, OperationBin, OperationData}; +use crate::commands::buffer::Buffer; +use crate::errors::Result; +use crate::msgpack::encoder::{pack_array_begin, pack_integer}; +use crate::ParticleType; + +/// Expression write Flags +pub enum ExpWriteFlags { + /// Default. Allow create or update. + Default = 0, + /// If bin does not exist, a new bin will be created. + /// If bin exists, the operation will be denied. + /// If bin exists, fail with Bin Exists + CreateOnly = 1, + /// If bin exists, the bin will be overwritten. + /// If bin does not exist, the operation will be denied. + /// If bin does not exist, fail with Bin Not Found + UpdateOnly = 2, + /// If expression results in nil value, then delete the bin. + /// Otherwise, return OP Not Applicable when NoFail is not set + AllowDelete = 3, + /// Do not raise error if operation is denied. + PolicyNoFail = 8, + /// Ignore failures caused by the expression resolving to unknown or a non-bin type. + EvalNoFail = 16 +} + +pub type ExpressionEncoder = Box, &ExpOperation) -> Result>; + +pub struct ExpOperation<'a>{ + pub encoder: ExpressionEncoder, + pub policy: i64, + pub exp: &'a FilterExpression, +} + +impl<'a> ExpOperation<'a> { + pub const fn particle_type(&self) -> ParticleType { + ParticleType::BLOB + } + + pub fn estimate_size(&self) -> Result { + let size: usize = (self.encoder)(&mut None, self)?; + Ok(size) + } + + pub fn write_to(&self, buffer: &mut Buffer) -> Result { + let size: usize = (self.encoder)(&mut Some(buffer), self)?; + Ok(size) + } +} + +/// Expression read Flags +pub enum ExpReadFlags { + /// Default + Default = 0, + /// Ignore failures caused by the expression resolving to unknown or a non-bin type. + EvalNoFail = 16 +} + +pub fn write<'a>(flags: ExpWriteFlags, bin: &'a str, exp: &'a FilterExpression) -> Operation<'a> { + let op = ExpOperation{ + encoder: Box::new(pack_write_exp), + policy: flags as i64, + exp + }; + Operation { + op: OperationType::ExpWrite, + ctx: &[], + bin: OperationBin::Name(bin), + data: OperationData::EXPOp(op) + } +} + +pub fn read(exp: &FilterExpression) -> Operation { + let op = ExpOperation { + encoder: Box::new(pack_read_exp), + policy: 0, + exp + }; + Operation { + op: OperationType::ExpRead, + ctx: &[], + bin: OperationBin::None, + data: OperationData::EXPOp(op) + } +} + +fn pack_write_exp(buf: &mut Option<&mut Buffer>, exp_op: &ExpOperation) -> Result{ + let mut size = 0; + size += pack_array_begin(buf, 2)?; + size += exp_op.exp.pack(buf)?; + size += pack_integer(buf, exp_op.policy)?; + Ok(size) +} + +fn pack_read_exp(buf: &mut Option<&mut Buffer>, exp_op: &ExpOperation) -> Result{ + let mut size = 0; + size += pack_array_begin(buf, 1)?; + size += exp_op.exp.pack(buf)?; + Ok(size) +} \ No newline at end of file diff --git a/src/operations/mod.rs b/src/operations/mod.rs index 66802135..d03c492f 100644 --- a/src/operations/mod.rs +++ b/src/operations/mod.rs @@ -23,6 +23,7 @@ pub mod hll; pub mod lists; pub mod maps; pub mod scalar; +pub mod exp; use self::cdt::CdtOperation; pub use self::maps::{MapOrder, MapPolicy, MapReturnType, MapWriteMode}; @@ -33,6 +34,7 @@ use crate::commands::ParticleType; use crate::errors::Result; use crate::operations::cdt_context::CdtContext; use crate::Value; +use crate::operations::exp::ExpOperation; #[derive(Clone, Copy)] #[doc(hidden)] @@ -42,6 +44,8 @@ pub enum OperationType { CdtRead = 3, CdtWrite = 4, Incr = 5, + ExpRead = 6, + ExpWrite = 7, Append = 9, Prepend = 10, Touch = 11, @@ -60,6 +64,7 @@ pub enum OperationData<'a> { CdtMapOp(CdtOperation<'a>), CdtBitOp(CdtOperation<'a>), HLLOp(CdtOperation<'a>), + EXPOp(ExpOperation<'a>) } #[doc(hidden)] @@ -99,6 +104,7 @@ impl<'a> Operation<'a> { size += match self.data { OperationData::None => 0, OperationData::Value(value) => value.estimate_size()?, + OperationData::EXPOp(ref exp_op) => exp_op.estimate_size()?, OperationData::CdtListOp(ref cdt_op) | OperationData::CdtMapOp(ref cdt_op) | OperationData::CdtBitOp(ref cdt_op) @@ -133,6 +139,10 @@ impl<'a> Operation<'a> { size += self.write_op_header_to(buffer, cdt_op.particle_type() as u8)?; size += cdt_op.write_to(buffer, self.ctx)?; } + OperationData::EXPOp(ref exp) => { + size += self.write_op_header_to(buffer, exp.particle_type() as u8)?; + size += exp.write_to(buffer)?; + } }; Ok(size) From 9c74a4b372866b055c5c67652575c5dacced1b7b Mon Sep 17 00:00:00 2001 From: Jonas Breuer Date: Fri, 26 Feb 2021 09:53:31 +0100 Subject: [PATCH 04/14] Cleaned up and fixed clippy warnings --- src/commands/buffer.rs | 3 +-- src/expressions/hll.rs | 13 +++++++-- src/expressions/mod.rs | 38 +++++++++++++------------- src/operations/exp.rs | 61 ++++++++++++++++++++++++++++++------------ src/operations/mod.rs | 6 ++--- 5 files changed, 78 insertions(+), 43 deletions(-) diff --git a/src/commands/buffer.rs b/src/commands/buffer.rs index b5a54b6e..ad979eeb 100644 --- a/src/commands/buffer.rs +++ b/src/commands/buffer.rs @@ -512,8 +512,7 @@ impl Buffer { _ => write_attr |= INFO2_WRITE, } - let each_op = - matches!(operation.data, OperationData::CdtMapOp(_) | OperationData::CdtBitOp(_) | OperationData::HLLOp(_) | OperationData::EXPOp(_)); + let each_op = matches!(operation.data, OperationData::CdtMapOp(_) | OperationData::CdtBitOp(_) | OperationData::HLLOp(_) | OperationData::EXPOp(_)); if policy.respond_per_each_op || each_op { write_attr |= INFO2_RESPOND_ALL_OPS; diff --git a/src/expressions/hll.rs b/src/expressions/hll.rs index 0595c9a9..4ea5f8a0 100644 --- a/src/expressions/hll.rs +++ b/src/expressions/hll.rs @@ -35,12 +35,21 @@ pub enum HllExpOp { } /// Create expression that creates a new HLL or resets an existing HLL. -pub fn init(policy: HLLPolicy, index_bit_count: FilterExpression, bin: FilterExpression) -> FilterExpression { +pub fn init( + policy: HLLPolicy, + index_bit_count: FilterExpression, + bin: FilterExpression, +) -> FilterExpression { init_with_min_hash(policy, index_bit_count, int_val(-1), bin) } /// Create expression that creates a new HLL or resets an existing HLL with minhash bits. -pub fn init_with_min_hash(policy: HLLPolicy, index_bit_count: FilterExpression, min_hash_count: FilterExpression, bin: FilterExpression) -> FilterExpression { +pub fn init_with_min_hash( + policy: HLLPolicy, + index_bit_count: FilterExpression, + min_hash_count: FilterExpression, + bin: FilterExpression, +) -> FilterExpression { add_write( bin, vec![ diff --git a/src/expressions/mod.rs b/src/expressions/mod.rs index d4a40e24..f55d8a1b 100644 --- a/src/expressions/mod.rs +++ b/src/expressions/mod.rs @@ -872,14 +872,14 @@ pub fn le(left: FilterExpression, right: FilterExpression) -> FilterExpression { } /// Create "add" (+) operator that applies to a variable number of expressions. -/// Return sum of all FilterExpressions given. All arguments must resolve to the same type (integer or float). +/// Return sum of all `FilterExpressions` given. All arguments must resolve to the same type (integer or float). /// Requires server version 5.6.0+. /// ``` /// use aerospike::expressions::{eq, num_add, int_bin, int_val}; /// // a + b + c == 10 /// eq(num_add(vec![int_bin("a".to_string()), int_bin("b".to_string()), int_bin("c".to_string())]), int_val(10)); /// ``` -pub fn num_add(exps: Vec) -> FilterExpression { +pub const fn num_add(exps: Vec) -> FilterExpression { FilterExpression { cmd: Some(ExpOp::Add), val: None, @@ -892,16 +892,16 @@ pub fn num_add(exps: Vec) -> FilterExpression { } /// Create "subtract" (-) operator that applies to a variable number of expressions. -/// If only one FilterExpression is provided, return the negation of that argument. -/// Otherwise, return the sum of the 2nd to Nth FilterExpression subtracted from the 1st -/// FilterExpression. All FilterExpressions must resolve to the same type (integer or float). +/// If only one `FilterExpressions` is provided, return the negation of that argument. +/// Otherwise, return the sum of the 2nd to Nth `FilterExpressions` subtracted from the 1st +/// `FilterExpressions`. All `FilterExpressions` must resolve to the same type (integer or float). /// Requires server version 5.6.0+. /// ``` /// use aerospike::expressions::{gt, num_sub, int_bin, int_val}; /// // a - b - c > 10 /// gt(num_sub(vec![int_bin("a".to_string()), int_bin("b".to_string()), int_bin("c".to_string())]), int_val(10)); /// ``` -pub fn num_sub(exps: Vec) -> FilterExpression { +pub const fn num_sub(exps: Vec) -> FilterExpression { FilterExpression { cmd: Some(ExpOp::Sub), val: None, @@ -914,15 +914,15 @@ pub fn num_sub(exps: Vec) -> FilterExpression { } /// Create "multiply" (*) operator that applies to a variable number of expressions. -/// Return the product of all FilterExpressions. If only one FilterExpressions is supplied, return -/// that FilterExpressions. All FilterExpressions must resolve to the same type (integer or float). +/// Return the product of all `FilterExpressions`. If only one `FilterExpressions` is supplied, return +/// that `FilterExpressions`. All `FilterExpressions` must resolve to the same type (integer or float). /// Requires server version 5.6.0+. /// ``` /// use aerospike::expressions::{lt, num_mul, int_val, int_bin}; /// // a * b * c < 100 /// lt(num_mul(vec![int_bin("a".to_string()), int_bin("b".to_string()), int_bin("c".to_string())]), int_val(100)); /// ``` -pub fn num_mul(exps: Vec) -> FilterExpression { +pub const fn num_mul(exps: Vec) -> FilterExpression { FilterExpression { cmd: Some(ExpOp::Mul), val: None, @@ -935,16 +935,16 @@ pub fn num_mul(exps: Vec) -> FilterExpression { } /// Create "divide" (/) operator that applies to a variable number of expressions. -/// If there is only one FilterExpressions, returns the reciprocal for that FilterExpressions. -/// Otherwise, return the first FilterExpressions divided by the product of the rest. -/// All FilterExpressions must resolve to the same type (integer or float). +/// If there is only one `FilterExpressions`, returns the reciprocal for that `FilterExpressions`. +/// Otherwise, return the first `FilterExpressions` divided by the product of the rest. +/// All `FilterExpressions` must resolve to the same type (integer or float). /// Requires server version 5.6.0+. /// ``` /// use aerospike::expressions::{lt, int_val, int_bin, num_div}; /// // a / b / c > 1 /// lt(num_div(vec![int_bin("a".to_string()), int_bin("b".to_string()), int_bin("c".to_string())]), int_val(1)); /// ``` -pub fn num_div(exps: Vec) -> FilterExpression { +pub const fn num_div(exps: Vec) -> FilterExpression { FilterExpression { cmd: Some(ExpOp::Div), val: None, @@ -1122,7 +1122,7 @@ pub fn to_float(num: FilterExpression) -> FilterExpression { /// use aerospike::expressions::{eq, int_val, int_and, int_bin}; /// eq(int_and(vec![int_bin("a".to_string()), int_val(0xff)]), int_val(0x11)); /// ``` -pub fn int_and(exps: Vec) -> FilterExpression { +pub const fn int_and(exps: Vec) -> FilterExpression { FilterExpression { cmd: Some(ExpOp::IntAnd), val: None, @@ -1142,7 +1142,7 @@ pub fn int_and(exps: Vec) -> FilterExpression { /// use aerospike::expressions::{eq, int_val, int_xor, int_bin}; /// eq(int_xor(vec![int_bin("a".to_string()), int_bin("b".to_string())]), int_val(16)); /// ``` -pub fn int_xor(exps: Vec) -> FilterExpression { +pub const fn int_xor(exps: Vec) -> FilterExpression { FilterExpression { cmd: Some(ExpOp::IntXor), val: None, @@ -1304,7 +1304,7 @@ pub fn int_rscan(value: FilterExpression, search: FilterExpression) -> FilterExp /// use aerospike::expressions::{int_val, int_bin, gt, min}; /// gt(min(vec![int_bin("a".to_string()),int_bin("b".to_string()),int_bin("c".to_string())]), int_val(0)); /// ``` -pub fn min(exps: Vec) -> FilterExpression { +pub const fn min(exps: Vec) -> FilterExpression { FilterExpression { cmd: Some(ExpOp::Min), val: None, @@ -1324,7 +1324,7 @@ pub fn min(exps: Vec) -> FilterExpression { /// use aerospike::expressions::{int_val, int_bin, gt, max}; /// gt(max(vec![int_bin("a".to_string()),int_bin("b".to_string()),int_bin("c".to_string())]), int_val(100)); /// ``` -pub fn max(exps: Vec) -> FilterExpression { +pub const fn max(exps: Vec) -> FilterExpression { FilterExpression { cmd: Some(ExpOp::Max), val: None, @@ -1357,7 +1357,7 @@ pub fn max(exps: Vec) -> FilterExpression { /// ] /// ); /// ``` -pub fn cond(exps: Vec) -> FilterExpression { +pub const fn cond(exps: Vec) -> FilterExpression { FilterExpression { cmd: Some(ExpOp::Cond), val: None, @@ -1384,7 +1384,7 @@ pub fn cond(exps: Vec) -> FilterExpression { /// ] /// ); /// ``` -pub fn exp_let(exps: Vec) -> FilterExpression { +pub const fn exp_let(exps: Vec) -> FilterExpression { FilterExpression { cmd: Some(ExpOp::Let), val: None, diff --git a/src/operations/exp.rs b/src/operations/exp.rs index a2549542..1ca336b1 100644 --- a/src/operations/exp.rs +++ b/src/operations/exp.rs @@ -1,8 +1,26 @@ -use crate::expressions::FilterExpression; -use crate::operations::{Operation, OperationType, OperationBin, OperationData}; +// Copyright 2015-2020 Aerospike, Inc. +// +// Portions may be licensed to Aerospike, Inc. under one or more contributor +// license agreements. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +//! Expression Operations. +//! This functions allow users to run `FilterExpressions` as Operate commands. + use crate::commands::buffer::Buffer; use crate::errors::Result; +use crate::expressions::FilterExpression; use crate::msgpack::encoder::{pack_array_begin, pack_integer}; +use crate::operations::{Operation, OperationBin, OperationData, OperationType}; use crate::ParticleType; /// Expression write Flags @@ -23,27 +41,30 @@ pub enum ExpWriteFlags { /// Do not raise error if operation is denied. PolicyNoFail = 8, /// Ignore failures caused by the expression resolving to unknown or a non-bin type. - EvalNoFail = 16 + EvalNoFail = 16, } +#[doc(hidden)] pub type ExpressionEncoder = Box, &ExpOperation) -> Result>; -pub struct ExpOperation<'a>{ +#[doc(hidden)] +pub struct ExpOperation<'a> { pub encoder: ExpressionEncoder, pub policy: i64, pub exp: &'a FilterExpression, } impl<'a> ExpOperation<'a> { + #[doc(hidden)] pub const fn particle_type(&self) -> ParticleType { ParticleType::BLOB } - + #[doc(hidden)] pub fn estimate_size(&self) -> Result { let size: usize = (self.encoder)(&mut None, self)?; Ok(size) } - + #[doc(hidden)] pub fn write_to(&self, buffer: &mut Buffer) -> Result { let size: usize = (self.encoder)(&mut Some(buffer), self)?; Ok(size) @@ -55,38 +76,44 @@ pub enum ExpReadFlags { /// Default Default = 0, /// Ignore failures caused by the expression resolving to unknown or a non-bin type. - EvalNoFail = 16 + EvalNoFail = 16, } -pub fn write<'a>(flags: ExpWriteFlags, bin: &'a str, exp: &'a FilterExpression) -> Operation<'a> { - let op = ExpOperation{ +/// Create operation that performs a expression that writes to record bin. +pub fn write_exp<'a>( + flags: ExpWriteFlags, + bin: &'a str, + exp: &'a FilterExpression, +) -> Operation<'a> { + let op = ExpOperation { encoder: Box::new(pack_write_exp), policy: flags as i64, - exp + exp, }; Operation { op: OperationType::ExpWrite, ctx: &[], bin: OperationBin::Name(bin), - data: OperationData::EXPOp(op) + data: OperationData::EXPOp(op), } } -pub fn read(exp: &FilterExpression) -> Operation { +/// Create operation that performs a read expression. +pub fn read_exp(exp: &FilterExpression) -> Operation { let op = ExpOperation { encoder: Box::new(pack_read_exp), policy: 0, - exp + exp, }; Operation { op: OperationType::ExpRead, ctx: &[], bin: OperationBin::None, - data: OperationData::EXPOp(op) + data: OperationData::EXPOp(op), } } -fn pack_write_exp(buf: &mut Option<&mut Buffer>, exp_op: &ExpOperation) -> Result{ +fn pack_write_exp(buf: &mut Option<&mut Buffer>, exp_op: &ExpOperation) -> Result { let mut size = 0; size += pack_array_begin(buf, 2)?; size += exp_op.exp.pack(buf)?; @@ -94,9 +121,9 @@ fn pack_write_exp(buf: &mut Option<&mut Buffer>, exp_op: &ExpOperation) -> Resul Ok(size) } -fn pack_read_exp(buf: &mut Option<&mut Buffer>, exp_op: &ExpOperation) -> Result{ +fn pack_read_exp(buf: &mut Option<&mut Buffer>, exp_op: &ExpOperation) -> Result { let mut size = 0; size += pack_array_begin(buf, 1)?; size += exp_op.exp.pack(buf)?; Ok(size) -} \ No newline at end of file +} diff --git a/src/operations/mod.rs b/src/operations/mod.rs index d03c492f..32da0368 100644 --- a/src/operations/mod.rs +++ b/src/operations/mod.rs @@ -19,11 +19,11 @@ pub mod bitwise; #[doc(hidden)] pub mod cdt; pub mod cdt_context; +pub mod exp; pub mod hll; pub mod lists; pub mod maps; pub mod scalar; -pub mod exp; use self::cdt::CdtOperation; pub use self::maps::{MapOrder, MapPolicy, MapReturnType, MapWriteMode}; @@ -33,8 +33,8 @@ use crate::commands::buffer::Buffer; use crate::commands::ParticleType; use crate::errors::Result; use crate::operations::cdt_context::CdtContext; -use crate::Value; use crate::operations::exp::ExpOperation; +use crate::Value; #[derive(Clone, Copy)] #[doc(hidden)] @@ -64,7 +64,7 @@ pub enum OperationData<'a> { CdtMapOp(CdtOperation<'a>), CdtBitOp(CdtOperation<'a>), HLLOp(CdtOperation<'a>), - EXPOp(ExpOperation<'a>) + EXPOp(ExpOperation<'a>), } #[doc(hidden)] From 50013931e40922d05af3decc74ce5a46ef233e00 Mon Sep 17 00:00:00 2001 From: Jonas Breuer Date: Fri, 26 Feb 2021 13:19:52 +0100 Subject: [PATCH 05/14] Fixed encoding for Def and added tests --- src/expressions/mod.rs | 2 +- tests/src/exp.rs | 243 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 244 insertions(+), 1 deletion(-) diff --git a/src/expressions/mod.rs b/src/expressions/mod.rs index f55d8a1b..9c89fd89 100644 --- a/src/expressions/mod.rs +++ b/src/expressions/mod.rs @@ -174,7 +174,7 @@ impl FilterExpression { if let Some(val) = &self.val { // DEF expression size += pack_value(buf, val)?; - exps[0].pack(buf)?; + size += exps[0].pack(buf)?; } else { // Normal Expressions match self.cmd.unwrap() { diff --git a/tests/src/exp.rs b/tests/src/exp.rs index 276684cc..bbe902ec 100644 --- a/tests/src/exp.rs +++ b/tests/src/exp.rs @@ -163,6 +163,249 @@ fn expression_data_types() { assert_eq!(count, 100, "BIN TYPE Test Failed"); } +#[test] +fn expression_aero_5_6() { + let _ = env_logger::try_init(); + + let set_name = create_test_set(EXPECTED); + + let rs = test_filter( + eq( + num_add(vec![int_bin("bin".to_string()), int_val(10)]), + int_val(20), + ), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 1, "NUM_ADD Test Failed"); + + let rs = test_filter( + eq( + num_sub(vec![int_bin("bin".to_string()), int_val(10)]), + int_val(20), + ), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 1, "NUM_SUB Test Failed"); + + let rs = test_filter( + eq( + num_mul(vec![int_bin("bin".to_string()), int_val(10)]), + int_val(20), + ), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 1, "NUM_MUL Test Failed"); + + let rs = test_filter( + gt( + num_div(vec![int_bin("bin".to_string()), int_val(5)]), + int_val(10), + ), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 45, "NUM_DIV Test Failed"); + + let rs = test_filter( + eq( + num_pow(float_bin("bin3".to_string()), float_val(2.0)), + float_val(4.0), + ), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 1, "NUM_POW Test Failed"); + + let rs = test_filter( + eq( + num_log(float_bin("bin3".to_string()), float_val(2.0)), + float_val(4.0), + ), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 1, "NUM_LOG Test Failed"); + + let rs = test_filter( + eq(num_mod(int_bin("bin".to_string()), int_val(10)), int_val(0)), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 10, "NUM_MOD Test Failed"); + + let rs = test_filter( + eq(num_abs(int_bin("bin".to_string())), int_val(1)), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 1, "NUM_ABS Test Failed"); + + let rs = test_filter( + eq(num_floor(float_bin("bin3".to_string())), float_val(2.0)), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 3, "NUM_FLOOR Test Failed"); + + let rs = test_filter( + eq(num_ceil(float_bin("bin3".to_string())), float_val(2.0)), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 3, "NUM_CEIL Test Failed"); + + let rs = test_filter( + eq(to_int(float_bin("bin3".to_string())), int_val(2)), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 3, "TO_INT Test Failed"); + + let rs = test_filter( + eq(to_float(int_bin("bin".to_string())), float_val(2.0)), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 1, "TO_FLOAT Test Failed"); + + let rs = test_filter( + eq( + int_and(vec![int_bin("bin".to_string()), int_val(0xff)]), + int_val(0x11), + ), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 1, "INT_AND Test Failed"); + + let rs = test_filter( + eq( + int_xor(vec![int_bin("bin".to_string()), int_val(10)]), + int_val(16), + ), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 1, "INT_XOR Test Failed"); + + let rs = test_filter( + eq(int_not(int_bin("bin".to_string())), int_val(-50)), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 1, "INT_NOT Test Failed"); + + let rs = test_filter( + gt( + int_lshift(int_bin("bin".to_string()), int_val(8)), + int_val(0xff), + ), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 99, "INT_LSHIFT Test Failed"); + + let rs = test_filter( + gt( + int_rshift(int_bin("bin".to_string()), int_val(1)), + int_val(0x2a), + ), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 14, "INT_RSHIFT Test Failed"); + + let rs = test_filter( + gt( + int_arshift(int_bin("bin".to_string()), int_val(1)), + int_val(0x2a), + ), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 14, "INT_ARSHIFT Test Failed"); + + let rs = test_filter( + eq(int_count(int_bin("bin".to_string())), int_val(3)), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 32, "INT_COUNT Test Failed"); + + let rs = test_filter( + gt( + int_lscan(int_bin("bin".to_string()), bool_val(true)), + int_val(60), + ), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 7, "INT_LSCAN Test Failed"); + + let rs = test_filter( + gt( + int_rscan(int_bin("bin".to_string()), bool_val(true)), + int_val(60), + ), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 87, "INT_RSCAN Test Failed"); + + let rs = test_filter( + eq( + min(vec![int_bin("bin".to_string()), int_val(10)]), + int_val(10), + ), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 90, "MIN Test Failed"); + + let rs = test_filter( + eq( + max(vec![int_bin("bin".to_string()), int_val(10)]), + int_val(10), + ), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 11, "MAX Test Failed"); + + let rs = test_filter( + gt( + cond(vec![ + eq(num_mod(int_bin("bin".to_string()), int_val(2)), int_val(0)), + num_add(vec![int_bin("bin".to_string()), int_val(100)]), + gt(num_mod(int_bin("bin".to_string()), int_val(2)), int_val(0)), + num_add(vec![int_bin("bin".to_string()), int_val(10)]), + int_val(-1), + ]), + int_val(100), + ), + &set_name, + ); + let count = count_results(rs); + assert_eq!(count, 54, "COND Test Failed"); + + let rs = test_filter( + exp_let(vec![ + def("x".to_string(), int_bin("bin".to_string())), + and(vec![ + lt(int_val(5), var("x".to_string())), + lt(var("x".to_string()), int_val(10)), + ]), + ]), + &set_name, + ); + + let count = count_results(rs); + assert_eq!(count, 4, "LET/DEF/VAR Test Failed"); +} + #[test] fn expression_rec_ops() { let _ = env_logger::try_init(); From 39243e3f49d7901f4edd2c9d7037ecd4cb2814f1 Mon Sep 17 00:00:00 2001 From: Jonas Breuer Date: Fri, 26 Feb 2021 18:47:47 +0100 Subject: [PATCH 06/14] Trying to get Expression Ops to work --- src/commands/buffer.rs | 1 - src/operations/exp.rs | 7 ++++--- src/operations/mod.rs | 1 - tests/src/exp_op.rs | 35 +++++++++++++++++++++++++++++++++++ tests/src/mod.rs | 1 + 5 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 tests/src/exp_op.rs diff --git a/src/commands/buffer.rs b/src/commands/buffer.rs index ad979eeb..37073084 100644 --- a/src/commands/buffer.rs +++ b/src/commands/buffer.rs @@ -554,7 +554,6 @@ impl Buffer { for operation in operations { operation.write_to(self)?; } - self.end() } diff --git a/src/operations/exp.rs b/src/operations/exp.rs index 1ca336b1..1de16db6 100644 --- a/src/operations/exp.rs +++ b/src/operations/exp.rs @@ -99,10 +99,10 @@ pub fn write_exp<'a>( } /// Create operation that performs a read expression. -pub fn read_exp(exp: &FilterExpression) -> Operation { +pub fn read_exp(exp: &FilterExpression, flags: ExpReadFlags) -> Operation { let op = ExpOperation { encoder: Box::new(pack_read_exp), - policy: 0, + policy: flags as i64, exp, }; Operation { @@ -123,7 +123,8 @@ fn pack_write_exp(buf: &mut Option<&mut Buffer>, exp_op: &ExpOperation) -> Resul fn pack_read_exp(buf: &mut Option<&mut Buffer>, exp_op: &ExpOperation) -> Result { let mut size = 0; - size += pack_array_begin(buf, 1)?; + size += pack_array_begin(buf, 2)?; size += exp_op.exp.pack(buf)?; + size += pack_integer(buf, exp_op.policy)?; Ok(size) } diff --git a/src/operations/mod.rs b/src/operations/mod.rs index 32da0368..1d090199 100644 --- a/src/operations/mod.rs +++ b/src/operations/mod.rs @@ -140,7 +140,6 @@ impl<'a> Operation<'a> { size += cdt_op.write_to(buffer, self.ctx)?; } OperationData::EXPOp(ref exp) => { - size += self.write_op_header_to(buffer, exp.particle_type() as u8)?; size += exp.write_to(buffer)?; } }; diff --git a/tests/src/exp_op.rs b/tests/src/exp_op.rs new file mode 100644 index 00000000..a1372f50 --- /dev/null +++ b/tests/src/exp_op.rs @@ -0,0 +1,35 @@ +use crate::common; +use aerospike::expressions::{int_bin, int_val, num_add}; +use aerospike::operations::exp::{read_exp, ExpReadFlags}; +use aerospike::{as_bin, as_key, as_val, Bins, ReadPolicy, Value, WritePolicy}; + +#[test] +fn exp_ops() { + let _ = env_logger::try_init(); + + let client = common::client(); + let namespace = common::namespace(); + let set_name = &common::rand_str(10); + + let policy = ReadPolicy::default(); + + let wpolicy = WritePolicy::default(); + let key = as_key!(namespace, set_name, -1); + let wbin = as_bin!("bin", as_val!(25)); + let bins = vec![&wbin]; + + client.delete(&wpolicy, &key).unwrap(); + + client.put(&wpolicy, &key, &bins).unwrap(); + let rec = client.get(&policy, &key, Bins::All).unwrap(); + assert_eq!(*rec.bins.get("bin").unwrap(), as_val!(25), "EXP OPs init failed"); + let flt = num_add(vec![ + int_bin("bin".to_string()), + int_val(4), + ]); + let ops = &vec![read_exp(&flt, ExpReadFlags::Default)]; + let rec = client.operate(&wpolicy, &key, ops); + println!("{:?}", rec); + let rec = rec.unwrap(); + assert_eq!(*rec.bins.get("bin").unwrap(), as_val!(35), "EXP OPs read failed"); +} diff --git a/tests/src/mod.rs b/tests/src/mod.rs index d48b3813..1d3765d9 100644 --- a/tests/src/mod.rs +++ b/tests/src/mod.rs @@ -22,6 +22,7 @@ mod exp_bitwise; mod exp_hll; mod exp_list; mod exp_map; +mod exp_op; mod hll; mod index; mod kv; From 08c91444549015c27d8d275ea0fd95f92fd54598 Mon Sep 17 00:00:00 2001 From: Jonas Breuer Date: Thu, 4 Mar 2021 03:00:57 +0100 Subject: [PATCH 07/14] Fixed ExpWriteFlags --- src/operations/exp.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/operations/exp.rs b/src/operations/exp.rs index 1de16db6..1f45c6a1 100644 --- a/src/operations/exp.rs +++ b/src/operations/exp.rs @@ -26,22 +26,22 @@ use crate::ParticleType; /// Expression write Flags pub enum ExpWriteFlags { /// Default. Allow create or update. - Default = 0, + Default = 0, /// If bin does not exist, a new bin will be created. /// If bin exists, the operation will be denied. /// If bin exists, fail with Bin Exists - CreateOnly = 1, + CreateOnly = 1 << 0, /// If bin exists, the bin will be overwritten. /// If bin does not exist, the operation will be denied. /// If bin does not exist, fail with Bin Not Found - UpdateOnly = 2, + UpdateOnly = 1 << 1, /// If expression results in nil value, then delete the bin. /// Otherwise, return OP Not Applicable when NoFail is not set - AllowDelete = 3, + AllowDelete = 1 << 2, /// Do not raise error if operation is denied. - PolicyNoFail = 8, + PolicyNoFail = 1 << 3, /// Ignore failures caused by the expression resolving to unknown or a non-bin type. - EvalNoFail = 16, + EvalNoFail = 1 << 4, } #[doc(hidden)] @@ -76,7 +76,7 @@ pub enum ExpReadFlags { /// Default Default = 0, /// Ignore failures caused by the expression resolving to unknown or a non-bin type. - EvalNoFail = 16, + EvalNoFail = 1 << 4, } /// Create operation that performs a expression that writes to record bin. From d2ac067d8b4c807559634d3436041e3645602d8f Mon Sep 17 00:00:00 2001 From: Jonas Breuer Date: Fri, 5 Mar 2021 20:50:09 +0100 Subject: [PATCH 08/14] Fixed ExpOps and added Tests --- src/operations/mod.rs | 7 ++++--- tests/src/exp_op.rs | 15 ++++++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/operations/mod.rs b/src/operations/mod.rs index 1d090199..50df7ba3 100644 --- a/src/operations/mod.rs +++ b/src/operations/mod.rs @@ -34,7 +34,7 @@ use crate::commands::ParticleType; use crate::errors::Result; use crate::operations::cdt_context::CdtContext; use crate::operations::exp::ExpOperation; -use crate::Value; +use crate::{Value}; #[derive(Clone, Copy)] #[doc(hidden)] @@ -44,8 +44,8 @@ pub enum OperationType { CdtRead = 3, CdtWrite = 4, Incr = 5, - ExpRead = 6, - ExpWrite = 7, + ExpRead = 7, + ExpWrite = 8, Append = 9, Prepend = 10, Touch = 11, @@ -140,6 +140,7 @@ impl<'a> Operation<'a> { size += cdt_op.write_to(buffer, self.ctx)?; } OperationData::EXPOp(ref exp) => { + size += self.write_op_header_to(buffer, ParticleType::BLOB as u8)?; size += exp.write_to(buffer)?; } }; diff --git a/tests/src/exp_op.rs b/tests/src/exp_op.rs index a1372f50..3e138081 100644 --- a/tests/src/exp_op.rs +++ b/tests/src/exp_op.rs @@ -1,7 +1,8 @@ use crate::common; use aerospike::expressions::{int_bin, int_val, num_add}; -use aerospike::operations::exp::{read_exp, ExpReadFlags}; +use aerospike::operations::exp::{read_exp, ExpReadFlags, write_exp, ExpWriteFlags}; use aerospike::{as_bin, as_key, as_val, Bins, ReadPolicy, Value, WritePolicy}; +use aerospike::operations::OperationType::ExpWrite; #[test] fn exp_ops() { @@ -29,7 +30,15 @@ fn exp_ops() { ]); let ops = &vec![read_exp(&flt, ExpReadFlags::Default)]; let rec = client.operate(&wpolicy, &key, ops); - println!("{:?}", rec); let rec = rec.unwrap(); - assert_eq!(*rec.bins.get("bin").unwrap(), as_val!(35), "EXP OPs read failed"); + + assert_eq!(*rec.bins.get("").unwrap(), as_val!(29), "EXP OPs read failed"); + + let flt2 = int_bin("bin2".to_string()); + let ops = &vec![write_exp(ExpWriteFlags::Default,"bin2", &flt), read_exp(&flt2, ExpReadFlags::Default)]; + + let rec = client.operate(&wpolicy, &key, ops); + let rec = rec.unwrap(); + + assert_eq!(*rec.bins.get("").unwrap(), as_val!(29), "EXP OPs write failed"); } From 47278d650388bc351e78ffe2489dcbed35784f1d Mon Sep 17 00:00:00 2001 From: Jonas Breuer Date: Sat, 20 Mar 2021 23:40:56 +0100 Subject: [PATCH 09/14] Added unknown expression --- src/expressions/mod.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/expressions/mod.rs b/src/expressions/mod.rs index 9c89fd89..2ef1e361 100644 --- a/src/expressions/mod.rs +++ b/src/expressions/mod.rs @@ -56,6 +56,7 @@ pub enum ExpType { #[derive(Debug, Clone, Copy)] #[doc(hidden)] pub enum ExpOp { + Unknown = 0, EQ = 1, NE = 2, GT = 3, @@ -1436,3 +1437,32 @@ pub fn var(name: String) -> FilterExpression { arguments: None, } } + +/// Create unknown value. Used to intentionally fail an expression. +/// The failure can be ignored with ExpWriteFlags EVAL_NO_FAIL +/// or ExpReadFlags EVAL_NO_FAIL. +/// Requires server version 5.6.0+. +/// +/// ``` +/// // double v = balance - 100.0; +/// // return (v > 0.0)? v : unknown; +/// use aerospike::expressions::{exp_let, def, num_sub, float_bin, float_val, cond, ge, var, unknown}; +/// exp_let( +/// vec![ +/// def("v".to_string(), num_sub(vec![float_bin("balance".to_string()), float_val(100.0)])), +/// cond(vec![ge(var("v".to_string()), float_val(0.0)), var("v".to_string())]), +/// unknown() +/// ] +/// ); +/// ``` +pub fn unknown() -> FilterExpression { + FilterExpression { + cmd: Some(ExpOp::Unknown), + val: None, + bin: None, + flags: None, + module: None, + exps: None, + arguments: None + } +} \ No newline at end of file From 7d8134004112ef2ed9dab73bb3704fd6c0333494 Mon Sep 17 00:00:00 2001 From: Jonas Breuer Date: Sun, 28 Mar 2021 20:20:31 +0200 Subject: [PATCH 10/14] Added name String to read_exp --- src/expressions/mod.rs | 10 +++++----- src/operations/exp.rs | 12 ++++++++---- src/operations/mod.rs | 2 +- tests/src/exp_op.rs | 34 +++++++++++++++++++++++----------- 4 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/expressions/mod.rs b/src/expressions/mod.rs index 2ef1e361..c17c04fc 100644 --- a/src/expressions/mod.rs +++ b/src/expressions/mod.rs @@ -1439,8 +1439,8 @@ pub fn var(name: String) -> FilterExpression { } /// Create unknown value. Used to intentionally fail an expression. -/// The failure can be ignored with ExpWriteFlags EVAL_NO_FAIL -/// or ExpReadFlags EVAL_NO_FAIL. +/// The failure can be ignored with `ExpWriteFlags` `EVAL_NO_FAIL` +/// or `ExpReadFlags` `EVAL_NO_FAIL`. /// Requires server version 5.6.0+. /// /// ``` @@ -1455,7 +1455,7 @@ pub fn var(name: String) -> FilterExpression { /// ] /// ); /// ``` -pub fn unknown() -> FilterExpression { +pub const fn unknown() -> FilterExpression { FilterExpression { cmd: Some(ExpOp::Unknown), val: None, @@ -1463,6 +1463,6 @@ pub fn unknown() -> FilterExpression { flags: None, module: None, exps: None, - arguments: None + arguments: None, } -} \ No newline at end of file +} diff --git a/src/operations/exp.rs b/src/operations/exp.rs index 1f45c6a1..114a6618 100644 --- a/src/operations/exp.rs +++ b/src/operations/exp.rs @@ -26,7 +26,7 @@ use crate::ParticleType; /// Expression write Flags pub enum ExpWriteFlags { /// Default. Allow create or update. - Default = 0, + Default = 0, /// If bin does not exist, a new bin will be created. /// If bin exists, the operation will be denied. /// If bin exists, fail with Bin Exists @@ -81,9 +81,9 @@ pub enum ExpReadFlags { /// Create operation that performs a expression that writes to record bin. pub fn write_exp<'a>( - flags: ExpWriteFlags, bin: &'a str, exp: &'a FilterExpression, + flags: ExpWriteFlags, ) -> Operation<'a> { let op = ExpOperation { encoder: Box::new(pack_write_exp), @@ -99,7 +99,11 @@ pub fn write_exp<'a>( } /// Create operation that performs a read expression. -pub fn read_exp(exp: &FilterExpression, flags: ExpReadFlags) -> Operation { +pub fn read_exp<'a>( + name: &'a str, + exp: &'a FilterExpression, + flags: ExpReadFlags, +) -> Operation<'a> { let op = ExpOperation { encoder: Box::new(pack_read_exp), policy: flags as i64, @@ -108,7 +112,7 @@ pub fn read_exp(exp: &FilterExpression, flags: ExpReadFlags) -> Operation { Operation { op: OperationType::ExpRead, ctx: &[], - bin: OperationBin::None, + bin: OperationBin::Name(name), data: OperationData::EXPOp(op), } } diff --git a/src/operations/mod.rs b/src/operations/mod.rs index 50df7ba3..57e38a50 100644 --- a/src/operations/mod.rs +++ b/src/operations/mod.rs @@ -34,7 +34,7 @@ use crate::commands::ParticleType; use crate::errors::Result; use crate::operations::cdt_context::CdtContext; use crate::operations::exp::ExpOperation; -use crate::{Value}; +use crate::Value; #[derive(Clone, Copy)] #[doc(hidden)] diff --git a/tests/src/exp_op.rs b/tests/src/exp_op.rs index 3e138081..b3f1d375 100644 --- a/tests/src/exp_op.rs +++ b/tests/src/exp_op.rs @@ -1,8 +1,8 @@ use crate::common; use aerospike::expressions::{int_bin, int_val, num_add}; -use aerospike::operations::exp::{read_exp, ExpReadFlags, write_exp, ExpWriteFlags}; -use aerospike::{as_bin, as_key, as_val, Bins, ReadPolicy, Value, WritePolicy}; +use aerospike::operations::exp::{read_exp, write_exp, ExpReadFlags, ExpWriteFlags}; use aerospike::operations::OperationType::ExpWrite; +use aerospike::{as_bin, as_key, as_val, Bins, ReadPolicy, Value, WritePolicy}; #[test] fn exp_ops() { @@ -23,22 +23,34 @@ fn exp_ops() { client.put(&wpolicy, &key, &bins).unwrap(); let rec = client.get(&policy, &key, Bins::All).unwrap(); - assert_eq!(*rec.bins.get("bin").unwrap(), as_val!(25), "EXP OPs init failed"); - let flt = num_add(vec![ - int_bin("bin".to_string()), - int_val(4), - ]); - let ops = &vec![read_exp(&flt, ExpReadFlags::Default)]; + assert_eq!( + *rec.bins.get("bin").unwrap(), + as_val!(25), + "EXP OPs init failed" + ); + let flt = num_add(vec![int_bin("bin".to_string()), int_val(4)]); + let ops = &vec![read_exp("example", &flt, ExpReadFlags::Default)]; let rec = client.operate(&wpolicy, &key, ops); let rec = rec.unwrap(); - assert_eq!(*rec.bins.get("").unwrap(), as_val!(29), "EXP OPs read failed"); + assert_eq!( + *rec.bins.get("example").unwrap(), + as_val!(29), + "EXP OPs read failed" + ); let flt2 = int_bin("bin2".to_string()); - let ops = &vec![write_exp(ExpWriteFlags::Default,"bin2", &flt), read_exp(&flt2, ExpReadFlags::Default)]; + let ops = &vec![ + write_exp("bin2", &flt, ExpWriteFlags::Default), + read_exp("example", &flt2, ExpReadFlags::Default), + ]; let rec = client.operate(&wpolicy, &key, ops); let rec = rec.unwrap(); - assert_eq!(*rec.bins.get("").unwrap(), as_val!(29), "EXP OPs write failed"); + assert_eq!( + *rec.bins.get("example").unwrap(), + as_val!(29), + "EXP OPs write failed" + ); } From 231a73ecf98740e1438e62b6cd384c31ebfe6daa Mon Sep 17 00:00:00 2001 From: Jonas Breuer Date: Wed, 16 Jun 2021 16:03:46 +0200 Subject: [PATCH 11/14] Update Version number to 1.1.0 to make CI run again --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c65111d3..6d75159f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aerospike" -version = "1.0.0" +version = "1.1.0" edition = "2018" authors = ["Khosrow Afroozeh ", "Jan Hecking "] description = "Aerospike Client for Rust" From 4ce8ef780e7a2d16b50a1994973969fd724c3e8e Mon Sep 17 00:00:00 2001 From: Jonas Breuer Date: Tue, 19 Oct 2021 01:47:42 +0200 Subject: [PATCH 12/14] Fix for buffer size when using contexts --- src/expressions/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/expressions/mod.rs b/src/expressions/mod.rs index c17c04fc..f907d2d4 100644 --- a/src/expressions/mod.rs +++ b/src/expressions/mod.rs @@ -230,13 +230,13 @@ impl FilterExpression { | ExpressionArgument::FilterExpression(_) => len += 1, ExpressionArgument::Context(ctx) => { if !ctx.is_empty() { - pack_array_begin(buf, 3)?; - pack_integer(buf, 0xff)?; - pack_array_begin(buf, ctx.len() * 2)?; + size += pack_array_begin(buf, 3)?; + size += pack_integer(buf, 0xff)?; + size += pack_array_begin(buf, ctx.len() * 2)?; for c in ctx { - pack_integer(buf, i64::from(c.id))?; - pack_value(buf, &c.value)?; + size += pack_integer(buf, i64::from(c.id))?; + size += pack_value(buf, &c.value)?; } } } From 33626fb8d33063026088298e4f0620b2a3bbea3e Mon Sep 17 00:00:00 2001 From: Jonas Breuer Date: Fri, 22 Oct 2021 20:33:50 +0200 Subject: [PATCH 13/14] Fixed compiler warnings --- src/commands/buffer.rs | 8 +++++++- tests/src/exp_op.rs | 3 +-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/commands/buffer.rs b/src/commands/buffer.rs index daa2de81..c2fa4f77 100644 --- a/src/commands/buffer.rs +++ b/src/commands/buffer.rs @@ -515,7 +515,13 @@ impl Buffer { _ => write_attr |= INFO2_WRITE, } - let each_op = matches!(operation.data, OperationData::CdtMapOp(_) | OperationData::CdtBitOp(_) | OperationData::HLLOp(_) | OperationData::EXPOp(_)); + let each_op = matches!( + operation.data, + OperationData::CdtMapOp(_) + | OperationData::CdtBitOp(_) + | OperationData::HLLOp(_) + | OperationData::EXPOp(_) + ); if policy.respond_per_each_op || each_op { write_attr |= INFO2_RESPOND_ALL_OPS; diff --git a/tests/src/exp_op.rs b/tests/src/exp_op.rs index b3f1d375..6187707d 100644 --- a/tests/src/exp_op.rs +++ b/tests/src/exp_op.rs @@ -1,8 +1,7 @@ use crate::common; use aerospike::expressions::{int_bin, int_val, num_add}; use aerospike::operations::exp::{read_exp, write_exp, ExpReadFlags, ExpWriteFlags}; -use aerospike::operations::OperationType::ExpWrite; -use aerospike::{as_bin, as_key, as_val, Bins, ReadPolicy, Value, WritePolicy}; +use aerospike::{as_bin, as_key, as_val, Bins, ReadPolicy, WritePolicy}; #[test] fn exp_ops() { From d7ce32bd30ce50b5c9c8ee8a02b6228b1c40ff95 Mon Sep 17 00:00:00 2001 From: Jonas Breuer Date: Fri, 22 Oct 2021 21:06:57 +0200 Subject: [PATCH 14/14] Changed string packing for variable expressions --- src/expressions/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/expressions/mod.rs b/src/expressions/mod.rs index f907d2d4..b8f0fca6 100644 --- a/src/expressions/mod.rs +++ b/src/expressions/mod.rs @@ -174,7 +174,7 @@ impl FilterExpression { let mut size = 0; if let Some(val) = &self.val { // DEF expression - size += pack_value(buf, val)?; + size += pack_raw_string(buf, &val.to_string())?; size += exps[0].pack(buf)?; } else { // Normal Expressions @@ -272,10 +272,10 @@ impl FilterExpression { // The name - Raw String is needed instead of the msgpack String that the pack_value method would use. size += pack_raw_string(buf, &self.val.clone().unwrap().to_string())?; } - ExpOp::BinType => { - // BinType encoder + ExpOp::BinType | ExpOp::Var => { + // BinType/Var encoder size += pack_array_begin(buf, 2)?; - // BinType Operation + // BinType/Var Operation size += pack_integer(buf, cmd as i64)?; // The name - Raw String is needed instead of the msgpack String that the pack_value method would use. size += pack_raw_string(buf, &self.val.clone().unwrap().to_string())?;