metabase_api_rs/core/models/
parameter.rs

1//! Parameter types for Cards and Dashboards
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6/// Parameter definition for cards and dashboards
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
8pub struct Parameter {
9    /// Unique identifier for the parameter
10    pub id: String,
11
12    /// Parameter type (e.g., "date/relative", "string/=", "number/>=")
13    #[serde(rename = "type")]
14    pub param_type: String,
15
16    /// Display name for the parameter
17    pub name: String,
18
19    /// URL slug for the parameter
20    pub slug: String,
21
22    /// Default value for the parameter
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub default: Option<Value>,
25
26    /// Whether the parameter is required
27    #[serde(default)]
28    pub required: bool,
29
30    /// Options for the parameter (for select/dropdown types)
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub options: Option<Vec<ParameterOption>>,
33
34    /// Values for list parameters
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub values_source_type: Option<String>,
37
38    /// Configuration for values source
39    #[serde(skip_serializing_if = "Option::is_none")]
40    pub values_source_config: Option<Value>,
41}
42
43/// Option for select/dropdown parameters
44#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
45pub struct ParameterOption {
46    /// Display text
47    pub name: String,
48
49    /// Actual value
50    pub value: Value,
51}
52
53/// Parameter mapping for dashboard cards
54#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
55pub struct ParameterMapping {
56    /// Parameter ID being mapped
57    pub parameter_id: String,
58
59    /// Card ID this mapping applies to
60    pub card_id: i64,
61
62    /// Target for the mapping
63    pub target: ParameterTarget,
64}
65
66/// Target for parameter mapping
67#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
68#[serde(untagged)]
69pub enum ParameterTarget {
70    /// Variable target (e.g., for SQL parameters)
71    Variable(VariableTarget),
72
73    /// Dimension target (e.g., for field filters)
74    Dimension(DimensionTarget),
75}
76
77/// Variable target for SQL parameters
78#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
79pub struct VariableTarget {
80    /// Type is always "variable" for this variant
81    #[serde(rename = "type")]
82    pub target_type: String,
83
84    /// Variable name
85    pub id: String,
86}
87
88/// Dimension target for field filters
89#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
90pub struct DimensionTarget {
91    /// Type is always "dimension" for this variant
92    #[serde(rename = "type")]
93    pub target_type: String,
94
95    /// Dimension specification [type, field_id/name, options]
96    pub id: Vec<Value>,
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102    use serde_json::json;
103
104    #[test]
105    fn test_parameter_serialization() {
106        let param = Parameter {
107            id: "date_param".to_string(),
108            param_type: "date/relative".to_string(),
109            name: "Date".to_string(),
110            slug: "date".to_string(),
111            default: Some(json!("past7days")),
112            required: false,
113            options: None,
114            values_source_type: None,
115            values_source_config: None,
116        };
117
118        let json = serde_json::to_value(&param).unwrap();
119        assert_eq!(json["id"], "date_param");
120        assert_eq!(json["type"], "date/relative");
121        assert_eq!(json["name"], "Date");
122        assert_eq!(json["slug"], "date");
123        assert_eq!(json["default"], "past7days");
124    }
125
126    #[test]
127    fn test_parameter_with_options() {
128        let param = Parameter {
129            id: "status_param".to_string(),
130            param_type: "string/=".to_string(),
131            name: "Status".to_string(),
132            slug: "status".to_string(),
133            default: Some(json!("active")),
134            required: true,
135            options: Some(vec![
136                ParameterOption {
137                    name: "Active".to_string(),
138                    value: json!("active"),
139                },
140                ParameterOption {
141                    name: "Inactive".to_string(),
142                    value: json!("inactive"),
143                },
144            ]),
145            values_source_type: None,
146            values_source_config: None,
147        };
148
149        let json = serde_json::to_value(&param).unwrap();
150        assert_eq!(json["required"], true);
151        assert!(json["options"].is_array());
152        assert_eq!(json["options"][0]["name"], "Active");
153        assert_eq!(json["options"][0]["value"], "active");
154    }
155
156    #[test]
157    fn test_variable_parameter_mapping() {
158        let mapping = ParameterMapping {
159            parameter_id: "date_param".to_string(),
160            card_id: 123,
161            target: ParameterTarget::Variable(VariableTarget {
162                target_type: "variable".to_string(),
163                id: "start_date".to_string(),
164            }),
165        };
166
167        let json = serde_json::to_value(&mapping).unwrap();
168        assert_eq!(json["parameter_id"], "date_param");
169        assert_eq!(json["card_id"], 123);
170        assert_eq!(json["target"]["type"], "variable");
171        assert_eq!(json["target"]["id"], "start_date");
172    }
173
174    #[test]
175    fn test_dimension_parameter_mapping() {
176        let mapping = ParameterMapping {
177            parameter_id: "category_param".to_string(),
178            card_id: 456,
179            target: ParameterTarget::Dimension(DimensionTarget {
180                target_type: "dimension".to_string(),
181                id: vec![json!("field"), json!(10), json!(null)],
182            }),
183        };
184
185        let json = serde_json::to_value(&mapping).unwrap();
186        assert_eq!(json["parameter_id"], "category_param");
187        assert_eq!(json["card_id"], 456);
188        assert_eq!(json["target"]["type"], "dimension");
189        assert!(json["target"]["id"].is_array());
190        assert_eq!(json["target"]["id"][0], "field");
191        assert_eq!(json["target"]["id"][1], 10);
192    }
193}