1use super::BindingValue;
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
14#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
15#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
16#[serde(tag = "service", rename_all = "lowercase")]
17pub enum KvBinding {
18 Dynamodb(DynamodbKvBinding),
20 Firestore(FirestoreKvBinding),
22 TableStorage(TableStorageKvBinding),
24 Redis(RedisKvBinding),
26 #[serde(rename = "local-kv")]
28 Local(LocalKvBinding),
29}
30
31#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
33#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
34#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
35#[serde(rename_all = "camelCase")]
36pub struct DynamodbKvBinding {
37 pub table_name: BindingValue<String>,
39 pub region: BindingValue<String>,
41 #[serde(skip_serializing_if = "Option::is_none")]
43 pub endpoint_url: Option<BindingValue<String>>,
44}
45
46#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
48#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
49#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
50#[serde(rename_all = "camelCase")]
51pub struct FirestoreKvBinding {
52 pub project_id: BindingValue<String>,
54 pub database_id: BindingValue<String>,
56 pub collection_name: BindingValue<String>,
58}
59
60#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
62#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
63#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
64#[serde(rename_all = "camelCase")]
65pub struct TableStorageKvBinding {
66 pub resource_group_name: BindingValue<String>,
68 pub account_name: BindingValue<String>,
70 pub table_name: BindingValue<String>,
72}
73
74#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
76#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
77#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
78#[serde(rename_all = "camelCase")]
79pub struct RedisKvBinding {
80 pub connection_url: BindingValue<String>,
82 #[serde(skip_serializing_if = "Option::is_none")]
84 pub key_prefix: Option<BindingValue<String>>,
85 #[serde(skip_serializing_if = "Option::is_none")]
87 pub database: Option<BindingValue<u8>>,
88}
89
90#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
92#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
93#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
94#[serde(rename_all = "camelCase")]
95pub struct LocalKvBinding {
96 pub data_dir: BindingValue<String>,
98 #[serde(skip_serializing_if = "Option::is_none")]
100 pub key_prefix: Option<BindingValue<String>>,
101}
102
103impl KvBinding {
104 pub fn dynamodb(
106 table_name: impl Into<BindingValue<String>>,
107 region: impl Into<BindingValue<String>>,
108 ) -> Self {
109 Self::Dynamodb(DynamodbKvBinding {
110 table_name: table_name.into(),
111 region: region.into(),
112 endpoint_url: None,
113 })
114 }
115
116 pub fn dynamodb_with_endpoint(
118 table_name: impl Into<BindingValue<String>>,
119 region: impl Into<BindingValue<String>>,
120 endpoint_url: impl Into<BindingValue<String>>,
121 ) -> Self {
122 Self::Dynamodb(DynamodbKvBinding {
123 table_name: table_name.into(),
124 region: region.into(),
125 endpoint_url: Some(endpoint_url.into()),
126 })
127 }
128
129 pub fn firestore(
131 project_id: impl Into<BindingValue<String>>,
132 database_id: impl Into<BindingValue<String>>,
133 collection_name: impl Into<BindingValue<String>>,
134 ) -> Self {
135 Self::Firestore(FirestoreKvBinding {
136 project_id: project_id.into(),
137 database_id: database_id.into(),
138 collection_name: collection_name.into(),
139 })
140 }
141
142 pub fn table_storage(
144 resource_group_name: impl Into<BindingValue<String>>,
145 account_name: impl Into<BindingValue<String>>,
146 table_name: impl Into<BindingValue<String>>,
147 ) -> Self {
148 Self::TableStorage(TableStorageKvBinding {
149 resource_group_name: resource_group_name.into(),
150 account_name: account_name.into(),
151 table_name: table_name.into(),
152 })
153 }
154
155 pub fn redis(connection_url: impl Into<BindingValue<String>>) -> Self {
157 Self::Redis(RedisKvBinding {
158 connection_url: connection_url.into(),
159 key_prefix: None,
160 database: None,
161 })
162 }
163
164 pub fn redis_with_options(
166 connection_url: impl Into<BindingValue<String>>,
167 key_prefix: Option<impl Into<BindingValue<String>>>,
168 database: Option<u8>,
169 ) -> Self {
170 Self::Redis(RedisKvBinding {
171 connection_url: connection_url.into(),
172 key_prefix: key_prefix.map(|p| p.into()),
173 database: database.map(BindingValue::value),
174 })
175 }
176
177 pub fn local(data_dir: impl Into<BindingValue<String>>) -> Self {
179 Self::Local(LocalKvBinding {
180 data_dir: data_dir.into(),
181 key_prefix: None,
182 })
183 }
184
185 pub fn local_with_prefix(
187 data_dir: impl Into<BindingValue<String>>,
188 key_prefix: impl Into<BindingValue<String>>,
189 ) -> Self {
190 Self::Local(LocalKvBinding {
191 data_dir: data_dir.into(),
192 key_prefix: Some(key_prefix.into()),
193 })
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200 use serde_json::json;
201
202 #[test]
203 fn test_dynamodb_binding() {
204 let binding = KvBinding::dynamodb("my-table", "us-east-1");
205
206 let json = serde_json::to_string(&binding).unwrap();
207 assert!(json.contains(r#""service":"dynamodb""#));
208
209 let deserialized: KvBinding = serde_json::from_str(&json).unwrap();
210 assert_eq!(binding, deserialized);
211 }
212
213 #[test]
214 fn test_firestore_binding() {
215 let binding = KvBinding::firestore("my-project", "(default)", "kv");
216
217 let json = serde_json::to_string(&binding).unwrap();
218 assert!(json.contains(r#""service":"firestore""#));
219
220 let deserialized: KvBinding = serde_json::from_str(&json).unwrap();
221 assert_eq!(binding, deserialized);
222 }
223
224 #[test]
225 fn test_table_storage_binding() {
226 let binding = KvBinding::table_storage("myresourcegroup", "myaccount", "mytable");
227
228 let json = serde_json::to_string(&binding).unwrap();
229 assert!(json.contains(r#""service":"tablestorage""#));
230
231 let deserialized: KvBinding = serde_json::from_str(&json).unwrap();
232 assert_eq!(binding, deserialized);
233 }
234
235 #[test]
236 fn test_redis_binding() {
237 let binding = KvBinding::redis("redis://localhost:6379");
238
239 let json = serde_json::to_string(&binding).unwrap();
240 assert!(json.contains(r#""service":"redis""#));
241
242 let deserialized: KvBinding = serde_json::from_str(&json).unwrap();
243 assert_eq!(binding, deserialized);
244 }
245
246 #[test]
247 fn test_local_binding() {
248 let binding = KvBinding::local("/tmp/kv");
249
250 let json = serde_json::to_string(&binding).unwrap();
251 assert!(json.contains(r#""service":"local-kv""#));
252
253 let deserialized: KvBinding = serde_json::from_str(&json).unwrap();
254 assert_eq!(binding, deserialized);
255 }
256
257 #[test]
258 fn test_binding_value_expressions() {
259 let binding = KvBinding::Dynamodb(DynamodbKvBinding {
260 table_name: BindingValue::expression(json!({"Ref": "MyTable"})),
261 region: BindingValue::value("us-east-1".to_string()),
262 endpoint_url: None,
263 });
264
265 let json = serde_json::to_string(&binding).unwrap();
266 let deserialized: KvBinding = serde_json::from_str(&json).unwrap();
267 assert_eq!(binding, deserialized);
268 }
269}