use derive_builder::Builder;
use serde::{Deserialize, Serialize};
use crate::common::enums::{
BinanceAlgoType, BinanceFuturesOrderType, BinanceIncomeType, BinanceMarginType,
BinancePositionSide, BinancePriceMatch, BinanceSelfTradePreventionMode, BinanceSide,
BinanceTimeInForce, BinanceWorkingType,
};
#[derive(Clone, Debug, Default, Deserialize, Serialize, Builder)]
#[builder(setter(into, strip_option), default)]
pub struct BinanceDepthParams {
pub symbol: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, Builder)]
#[builder(setter(into, strip_option), default)]
pub struct BinanceTradesParams {
pub symbol: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, Builder)]
#[builder(setter(into, strip_option), default)]
pub struct BinanceKlinesParams {
pub symbol: String,
pub interval: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "startTime")]
pub start_time: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "endTime")]
pub end_time: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
}
#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
#[builder(default)]
#[builder(setter(into, strip_option))]
pub struct BinanceTicker24hrParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
#[builder(default)]
#[builder(setter(into, strip_option))]
pub struct BinanceBookTickerParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
#[builder(default)]
#[builder(setter(into, strip_option))]
pub struct BinanceMarkPriceParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
#[builder(default)]
#[builder(setter(into, strip_option))]
pub struct BinanceFundingRateParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol: Option<String>,
#[serde(rename = "startTime", skip_serializing_if = "Option::is_none")]
pub start_time: Option<i64>,
#[serde(rename = "endTime", skip_serializing_if = "Option::is_none")]
pub end_time: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
}
#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
#[builder(setter(into))]
pub struct BinanceOpenInterestParams {
pub symbol: String,
}
#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
#[builder(default)]
#[builder(setter(into, strip_option))]
pub struct BinanceFuturesBalanceParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub asset: Option<String>,
#[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
pub recv_window: Option<u64>,
}
#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
#[builder(default)]
#[builder(setter(into, strip_option))]
pub struct BinancePositionRiskParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol: Option<String>,
#[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
pub recv_window: Option<u64>,
}
#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
#[builder(default)]
#[builder(setter(into, strip_option))]
pub struct BinanceIncomeHistoryParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol: Option<String>,
#[serde(rename = "incomeType", skip_serializing_if = "Option::is_none")]
pub income_type: Option<BinanceIncomeType>,
#[serde(rename = "startTime", skip_serializing_if = "Option::is_none")]
pub start_time: Option<i64>,
#[serde(rename = "endTime", skip_serializing_if = "Option::is_none")]
pub end_time: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
#[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
pub recv_window: Option<u64>,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, Builder)]
#[builder(setter(into, strip_option), default)]
pub struct BinanceUserTradesParams {
pub symbol: String,
#[serde(rename = "orderId", skip_serializing_if = "Option::is_none")]
pub order_id: Option<i64>,
#[serde(rename = "startTime", skip_serializing_if = "Option::is_none")]
pub start_time: Option<i64>,
#[serde(rename = "endTime", skip_serializing_if = "Option::is_none")]
pub end_time: Option<i64>,
#[serde(rename = "fromId", skip_serializing_if = "Option::is_none")]
pub from_id: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
#[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
pub recv_window: Option<u64>,
}
#[derive(Clone, Debug, Deserialize, Serialize, Default, Builder)]
#[builder(default)]
#[builder(setter(into, strip_option))]
pub struct BinanceOpenOrdersParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol: Option<String>,
#[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
pub recv_window: Option<u64>,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, Builder)]
#[builder(setter(into, strip_option), default)]
pub struct BinanceOrderQueryParams {
pub symbol: String,
#[serde(rename = "orderId", skip_serializing_if = "Option::is_none")]
pub order_id: Option<i64>,
#[serde(rename = "origClientOrderId", skip_serializing_if = "Option::is_none")]
pub orig_client_order_id: Option<String>,
#[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
pub recv_window: Option<u64>,
}
#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
#[builder(setter(into, strip_option))]
pub struct BinanceNewOrderParams {
pub symbol: String,
pub side: BinanceSide,
#[serde(rename = "type")]
pub order_type: BinanceFuturesOrderType,
#[serde(rename = "positionSide", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub position_side: Option<BinancePositionSide>,
#[serde(rename = "timeInForce", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub time_in_force: Option<BinanceTimeInForce>,
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub quantity: Option<String>,
#[serde(rename = "reduceOnly", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub reduce_only: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub price: Option<String>,
#[serde(rename = "newClientOrderId", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub new_client_order_id: Option<String>,
#[serde(rename = "stopPrice", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub stop_price: Option<String>,
#[serde(rename = "closePosition", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub close_position: Option<bool>,
#[serde(rename = "activationPrice", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub activation_price: Option<String>,
#[serde(rename = "callbackRate", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub callback_rate: Option<String>,
#[serde(rename = "workingType", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub working_type: Option<BinanceWorkingType>,
#[serde(rename = "priceProtect", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub price_protect: Option<bool>,
#[serde(rename = "newOrderRespType", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub new_order_resp_type: Option<String>,
#[serde(rename = "goodTillDate", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub good_till_date: Option<i64>,
#[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub recv_window: Option<u64>,
#[serde(rename = "priceMatch", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub price_match: Option<BinancePriceMatch>,
#[serde(
rename = "selfTradePreventionMode",
skip_serializing_if = "Option::is_none"
)]
#[builder(default)]
pub self_trade_prevention_mode: Option<BinanceSelfTradePreventionMode>,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, Builder)]
#[builder(setter(into, strip_option), default)]
pub struct BinanceCancelOrderParams {
pub symbol: String,
#[serde(rename = "orderId", skip_serializing_if = "Option::is_none")]
pub order_id: Option<i64>,
#[serde(rename = "origClientOrderId", skip_serializing_if = "Option::is_none")]
pub orig_client_order_id: Option<String>,
#[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
pub recv_window: Option<u64>,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, Builder)]
#[builder(setter(into, strip_option), default)]
pub struct BinanceCancelAllOrdersParams {
pub symbol: String,
#[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
pub recv_window: Option<u64>,
}
#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
#[builder(setter(into, strip_option))]
pub struct BinanceModifyOrderParams {
pub symbol: String,
#[serde(rename = "orderId", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub order_id: Option<i64>,
#[serde(rename = "origClientOrderId", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub orig_client_order_id: Option<String>,
pub side: BinanceSide,
pub quantity: String,
pub price: String,
#[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub recv_window: Option<u64>,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, Builder)]
#[builder(setter(into, strip_option), default)]
pub struct BinanceAllOrdersParams {
pub symbol: String,
#[serde(rename = "orderId", skip_serializing_if = "Option::is_none")]
pub order_id: Option<i64>,
#[serde(rename = "startTime", skip_serializing_if = "Option::is_none")]
pub start_time: Option<i64>,
#[serde(rename = "endTime", skip_serializing_if = "Option::is_none")]
pub end_time: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
#[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
pub recv_window: Option<u64>,
}
#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
#[builder(setter(into))]
pub struct BinanceSetLeverageParams {
pub symbol: String,
pub leverage: u32,
#[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub recv_window: Option<u64>,
}
#[derive(Clone, Debug, Deserialize, Serialize, Builder)]
#[builder(setter(into))]
pub struct BinanceSetMarginTypeParams {
pub symbol: String,
#[serde(rename = "marginType")]
pub margin_type: BinanceMarginType,
#[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub recv_window: Option<u64>,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BatchOrderItem {
pub symbol: String,
pub side: String,
#[serde(rename = "type")]
pub order_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub time_in_force: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub quantity: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reduce_only: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_client_order_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub position_side: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub activation_price: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub callback_rate: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub working_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub price_protect: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub close_position: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub good_till_date: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub price_match: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub self_trade_prevention_mode: Option<String>,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BatchCancelItem {
pub symbol: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub order_id: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub orig_client_order_id: Option<String>,
}
impl BatchCancelItem {
#[must_use]
pub fn by_order_id(symbol: impl Into<String>, order_id: i64) -> Self {
Self {
symbol: symbol.into(),
order_id: Some(order_id),
orig_client_order_id: None,
}
}
#[must_use]
pub fn by_client_order_id(
symbol: impl Into<String>,
client_order_id: impl Into<String>,
) -> Self {
Self {
symbol: symbol.into(),
order_id: None,
orig_client_order_id: Some(client_order_id.into()),
}
}
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BatchModifyItem {
pub symbol: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub order_id: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub orig_client_order_id: Option<String>,
pub side: String,
pub quantity: String,
pub price: String,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ListenKeyParams {
pub listen_key: String,
}
#[derive(Clone, Debug, Serialize, Builder)]
#[builder(setter(into, strip_option))]
#[serde(rename_all = "camelCase")]
pub struct BinanceNewAlgoOrderParams {
pub symbol: String,
pub side: BinanceSide,
#[serde(rename = "type")]
pub order_type: BinanceFuturesOrderType,
#[serde(rename = "algoType")]
pub algo_type: BinanceAlgoType,
#[serde(rename = "positionSide", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub position_side: Option<BinancePositionSide>,
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub quantity: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub price: Option<String>,
#[serde(rename = "triggerPrice", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub trigger_price: Option<String>,
#[serde(rename = "timeInForce", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub time_in_force: Option<BinanceTimeInForce>,
#[serde(rename = "workingType", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub working_type: Option<BinanceWorkingType>,
#[serde(rename = "closePosition", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub close_position: Option<bool>,
#[serde(rename = "priceProtect", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub price_protect: Option<bool>,
#[serde(rename = "reduceOnly", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub reduce_only: Option<bool>,
#[serde(rename = "activatePrice", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub activation_price: Option<String>,
#[serde(rename = "callbackRate", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub callback_rate: Option<String>,
#[serde(rename = "clientAlgoId", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub client_algo_id: Option<String>,
#[serde(rename = "goodTillDate", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub good_till_date: Option<i64>,
#[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub recv_window: Option<u64>,
}
#[derive(Clone, Debug, Default, Serialize, Builder)]
#[builder(setter(into, strip_option), default)]
#[serde(rename_all = "camelCase")]
pub struct BinanceAlgoOrderQueryParams {
#[serde(rename = "algoId", skip_serializing_if = "Option::is_none")]
pub algo_id: Option<i64>,
#[serde(rename = "clientAlgoId", skip_serializing_if = "Option::is_none")]
pub client_algo_id: Option<String>,
#[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
pub recv_window: Option<u64>,
}
#[derive(Clone, Debug, Default, Serialize, Builder)]
#[builder(setter(into, strip_option), default)]
#[serde(rename_all = "camelCase")]
pub struct BinanceOpenAlgoOrdersParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol: Option<String>,
#[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
pub recv_window: Option<u64>,
}
#[derive(Clone, Debug, Serialize, Builder)]
#[builder(setter(into, strip_option))]
#[serde(rename_all = "camelCase")]
pub struct BinanceAllAlgoOrdersParams {
pub symbol: String,
#[serde(rename = "startTime", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub start_time: Option<i64>,
#[serde(rename = "endTime", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub end_time: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub page: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub limit: Option<u32>,
#[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub recv_window: Option<u64>,
}
#[derive(Clone, Debug, Serialize, Builder)]
#[builder(setter(into, strip_option))]
#[serde(rename_all = "camelCase")]
pub struct BinanceCancelAllAlgoOrdersParams {
pub symbol: String,
#[serde(rename = "recvWindow", skip_serializing_if = "Option::is_none")]
#[builder(default)]
pub recv_window: Option<u64>,
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
#[rstest]
fn test_depth_params_builder() {
let params = BinanceDepthParamsBuilder::default()
.symbol("BTCUSDT")
.limit(100u32)
.build()
.unwrap();
assert_eq!(params.symbol, "BTCUSDT");
assert_eq!(params.limit, Some(100));
}
#[rstest]
fn test_ticker_params_serialization() {
let params = BinanceTicker24hrParams {
symbol: Some("BTCUSDT".to_string()),
};
let serialized = serde_urlencoded::to_string(¶ms).unwrap();
assert_eq!(serialized, "symbol=BTCUSDT");
}
#[rstest]
fn test_order_query_params_builder() {
let params = BinanceOrderQueryParamsBuilder::default()
.symbol("BTCUSDT")
.order_id(12345_i64)
.recv_window(5_000_u64)
.build()
.unwrap();
assert_eq!(params.symbol, "BTCUSDT");
assert_eq!(params.order_id, Some(12345));
assert_eq!(params.recv_window, Some(5_000));
}
#[rstest]
fn test_income_history_params_serialization() {
let params = BinanceIncomeHistoryParamsBuilder::default()
.symbol("ETHUSDT")
.income_type(BinanceIncomeType::FundingFee)
.limit(50_u32)
.build()
.unwrap();
let serialized = serde_urlencoded::to_string(¶ms).unwrap();
assert_eq!(serialized, "symbol=ETHUSDT&incomeType=FUNDING_FEE&limit=50");
}
#[rstest]
fn test_open_orders_params_builder() {
let params = BinanceOpenOrdersParamsBuilder::default()
.symbol("BNBUSDT")
.build()
.unwrap();
assert_eq!(params.symbol.as_deref(), Some("BNBUSDT"));
assert!(params.recv_window.is_none());
}
#[rstest]
fn test_new_algo_order_params_serialization_uses_activate_price() {
let params = BinanceNewAlgoOrderParamsBuilder::default()
.symbol("ETHUSDT")
.side(BinanceSide::Sell)
.order_type(BinanceFuturesOrderType::TrailingStopMarket)
.algo_type(BinanceAlgoType::Conditional)
.quantity("0.1")
.activation_price("10000.00")
.callback_rate("0.25")
.build()
.unwrap();
let serialized = serde_urlencoded::to_string(¶ms).unwrap();
let query: std::collections::HashMap<String, String> =
serde_urlencoded::from_str(&serialized).unwrap();
assert_eq!(query.get("activatePrice"), Some(&"10000.00".to_string()));
assert_eq!(query.get("callbackRate"), Some(&"0.25".to_string()));
assert!(!query.contains_key("activationPrice"));
}
#[rstest]
fn test_new_order_params_with_price_match_serializes_correctly() {
let params = BinanceNewOrderParams {
symbol: "BTCUSDT".to_string(),
side: BinanceSide::Buy,
order_type: BinanceFuturesOrderType::Limit,
time_in_force: Some(BinanceTimeInForce::Gtc),
quantity: Some("0.001".to_string()),
price: None,
new_client_order_id: Some("test-order-001".to_string()),
stop_price: None,
reduce_only: None,
position_side: None,
close_position: None,
activation_price: None,
callback_rate: None,
working_type: None,
price_protect: None,
new_order_resp_type: None,
good_till_date: None,
recv_window: None,
price_match: Some(BinancePriceMatch::Opponent5),
self_trade_prevention_mode: None,
};
let serialized = serde_urlencoded::to_string(¶ms).unwrap();
let query: std::collections::HashMap<String, String> =
serde_urlencoded::from_str(&serialized).unwrap();
assert_eq!(query.get("priceMatch"), Some(&"OPPONENT_5".to_string()));
assert!(!query.contains_key("price"));
assert_eq!(query.get("symbol"), Some(&"BTCUSDT".to_string()));
assert_eq!(query.get("side"), Some(&"BUY".to_string()));
assert_eq!(query.get("type"), Some(&"LIMIT".to_string()));
}
#[rstest]
fn test_new_order_params_without_price_match_omits_field() {
let params = BinanceNewOrderParams {
symbol: "BTCUSDT".to_string(),
side: BinanceSide::Buy,
order_type: BinanceFuturesOrderType::Limit,
time_in_force: Some(BinanceTimeInForce::Gtc),
quantity: Some("0.001".to_string()),
price: Some("50000.00".to_string()),
new_client_order_id: Some("test-order-002".to_string()),
stop_price: None,
reduce_only: None,
position_side: None,
close_position: None,
activation_price: None,
callback_rate: None,
working_type: None,
price_protect: None,
new_order_resp_type: None,
good_till_date: None,
recv_window: None,
price_match: None,
self_trade_prevention_mode: None,
};
let serialized = serde_urlencoded::to_string(¶ms).unwrap();
let query: std::collections::HashMap<String, String> =
serde_urlencoded::from_str(&serialized).unwrap();
assert!(!query.contains_key("priceMatch"));
assert_eq!(query.get("price"), Some(&"50000.00".to_string()));
}
}