azure_functions/bindings/
generic_output.rs

1use crate::{
2    generic::Value,
3    rpc::{typed_data::Data, TypedData},
4};
5
6/// Represents a generic output binding.
7///
8/// The following binding attributes are supported:
9///
10/// | Name                    | Description                                                                                                                |
11/// |-------------------------|----------------------------------------------------------------------------------------------------------------------------|
12/// | `type`                  | The binding type.                                                                                                          |
13/// | `name`                  | The name of the parameter being bound.                                                                                     |
14/// | `*`                     | The additional binding attributes specific to the binding type. Supported value types are strings, booleans, and integers. |
15///
16/// # Examples
17///
18/// An example of using a `GenericOutput` binding instead of a `CosmosDbDocument` binding:
19///
20/// ```rust
21/// use azure_functions::{
22///     bindings::{GenericOutput, HttpRequest, HttpResponse},
23///     func,
24/// };
25/// use serde_json::json;
26///
27/// #[func]
28/// #[binding(name = "req", route = "create/{id}")]
29/// #[binding(
30///     type = "cosmosDB",
31///     name = "output1",
32///     connectionStringSetting = "connection",
33///     databaseName = "exampledb",
34///     collectionName = "documents",
35///     createIfNotExists = true
36/// )]
37/// pub fn create_document(req: HttpRequest) -> (HttpResponse, GenericOutput) {
38///     (
39///         "Document was created.".into(),
40///         json!({
41///             "id": req.route_params().get("id").unwrap(),
42///             "name": req.query_params().get("name").map_or("stranger", |x| x)
43///         })
44///         .into(),
45///     )
46/// }
47/// ```
48#[derive(Debug, Clone)]
49pub struct GenericOutput {
50    /// The output binding data.
51    pub data: Value,
52}
53
54impl From<&str> for GenericOutput {
55    fn from(s: &str) -> Self {
56        GenericOutput {
57            data: Value::String(s.to_owned()),
58        }
59    }
60}
61
62impl From<String> for GenericOutput {
63    fn from(s: String) -> Self {
64        GenericOutput {
65            data: Value::String(s),
66        }
67    }
68}
69
70impl From<serde_json::Value> for GenericOutput {
71    fn from(value: serde_json::Value) -> Self {
72        GenericOutput {
73            data: Value::Json(value),
74        }
75    }
76}
77
78impl From<Vec<u8>> for GenericOutput {
79    fn from(bytes: Vec<u8>) -> Self {
80        GenericOutput {
81            data: Value::Bytes(bytes),
82        }
83    }
84}
85
86impl From<i64> for GenericOutput {
87    fn from(integer: i64) -> Self {
88        GenericOutput {
89            data: Value::Integer(integer),
90        }
91    }
92}
93
94impl From<f64> for GenericOutput {
95    fn from(double: f64) -> Self {
96        GenericOutput {
97            data: Value::Double(double),
98        }
99    }
100}
101
102#[doc(hidden)]
103impl Into<TypedData> for GenericOutput {
104    fn into(self) -> TypedData {
105        match self.data {
106            Value::None => TypedData { data: None },
107            Value::String(s) => TypedData {
108                data: Some(Data::String(s)),
109            },
110            Value::Json(v) => TypedData {
111                data: Some(Data::Json(v.to_string())),
112            },
113            Value::Bytes(b) => TypedData {
114                data: Some(Data::Bytes(b)),
115            },
116            Value::Integer(i) => TypedData {
117                data: Some(Data::Int(i)),
118            },
119            Value::Double(d) => TypedData {
120                data: Some(Data::Double(d)),
121            },
122        }
123    }
124}
125
126#[cfg(test)]
127mod tests {
128    use super::*;
129    use crate::rpc::typed_data::Data;
130    use serde_json::json;
131
132    #[test]
133    fn it_converts_from_str() {
134        let s = "hello world";
135
136        let binding: GenericOutput = s.into();
137
138        assert_eq!(binding.data, Value::String(s.to_owned()));
139    }
140
141    #[test]
142    fn it_converts_from_string() {
143        let s = "hello world".to_string();
144
145        let binding: GenericOutput = s.clone().into();
146
147        assert_eq!(binding.data, Value::String(s));
148    }
149
150    #[test]
151    fn it_converts_from_value() {
152        let value = json!({ "foo": "bar" });
153
154        let binding: GenericOutput = value.clone().into();
155
156        assert_eq!(binding.data, Value::Json(value));
157    }
158
159    #[test]
160    fn it_converts_from_bytes() {
161        let value = vec![1, 2, 3];
162
163        let binding: GenericOutput = value.clone().into();
164
165        assert_eq!(binding.data, Value::Bytes(value));
166    }
167
168    #[test]
169    fn it_converts_from_integer() {
170        let value = 12345;
171
172        let binding: GenericOutput = value.into();
173
174        assert_eq!(binding.data, Value::Integer(value));
175    }
176
177    #[test]
178    fn it_converts_from_double() {
179        let value = 12345.6;
180
181        let binding: GenericOutput = value.into();
182
183        assert_eq!(binding.data, Value::Double(value));
184    }
185
186    #[test]
187    fn it_converts_to_typed_data() {
188        let data: TypedData = GenericOutput {
189            data: Value::Json(json!({ "foo": "bar" })),
190        }
191        .into();
192
193        assert_eq!(data.data, Some(Data::Json(r#"{"foo":"bar"}"#.to_owned())));
194    }
195}