use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct Parameter {
pub id: String,
#[serde(rename = "type")]
pub param_type: String,
pub name: String,
pub slug: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub default: Option<Value>,
#[serde(default)]
pub required: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub options: Option<Vec<ParameterOption>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub values_source_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub values_source_config: Option<Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ParameterOption {
pub name: String,
pub value: Value,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ParameterMapping {
pub parameter_id: String,
pub card_id: i64,
pub target: ParameterTarget,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(untagged)]
pub enum ParameterTarget {
Variable(VariableTarget),
Dimension(DimensionTarget),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct VariableTarget {
#[serde(rename = "type")]
pub target_type: String,
pub id: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct DimensionTarget {
#[serde(rename = "type")]
pub target_type: String,
pub id: Vec<Value>,
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_parameter_serialization() {
let param = Parameter {
id: "date_param".to_string(),
param_type: "date/relative".to_string(),
name: "Date".to_string(),
slug: "date".to_string(),
default: Some(json!("past7days")),
required: false,
options: None,
values_source_type: None,
values_source_config: None,
};
let json = serde_json::to_value(¶m).unwrap();
assert_eq!(json["id"], "date_param");
assert_eq!(json["type"], "date/relative");
assert_eq!(json["name"], "Date");
assert_eq!(json["slug"], "date");
assert_eq!(json["default"], "past7days");
}
#[test]
fn test_parameter_with_options() {
let param = Parameter {
id: "status_param".to_string(),
param_type: "string/=".to_string(),
name: "Status".to_string(),
slug: "status".to_string(),
default: Some(json!("active")),
required: true,
options: Some(vec![
ParameterOption {
name: "Active".to_string(),
value: json!("active"),
},
ParameterOption {
name: "Inactive".to_string(),
value: json!("inactive"),
},
]),
values_source_type: None,
values_source_config: None,
};
let json = serde_json::to_value(¶m).unwrap();
assert_eq!(json["required"], true);
assert!(json["options"].is_array());
assert_eq!(json["options"][0]["name"], "Active");
assert_eq!(json["options"][0]["value"], "active");
}
#[test]
fn test_variable_parameter_mapping() {
let mapping = ParameterMapping {
parameter_id: "date_param".to_string(),
card_id: 123,
target: ParameterTarget::Variable(VariableTarget {
target_type: "variable".to_string(),
id: "start_date".to_string(),
}),
};
let json = serde_json::to_value(&mapping).unwrap();
assert_eq!(json["parameter_id"], "date_param");
assert_eq!(json["card_id"], 123);
assert_eq!(json["target"]["type"], "variable");
assert_eq!(json["target"]["id"], "start_date");
}
#[test]
fn test_dimension_parameter_mapping() {
let mapping = ParameterMapping {
parameter_id: "category_param".to_string(),
card_id: 456,
target: ParameterTarget::Dimension(DimensionTarget {
target_type: "dimension".to_string(),
id: vec![json!("field"), json!(10), json!(null)],
}),
};
let json = serde_json::to_value(&mapping).unwrap();
assert_eq!(json["parameter_id"], "category_param");
assert_eq!(json["card_id"], 456);
assert_eq!(json["target"]["type"], "dimension");
assert!(json["target"]["id"].is_array());
assert_eq!(json["target"]["id"][0], "field");
assert_eq!(json["target"]["id"][1], 10);
}
}