Skip to main content

postgrest_parser/parser/
body.rs

1use crate::ast::InsertValues;
2use crate::error::{Error, ParseError};
3use serde_json::Value;
4use std::collections::HashMap;
5
6/// Parses a JSON body string into a serde_json::Value
7///
8/// # Arguments
9///
10/// * `body` - JSON string representing the request body
11///
12/// # Examples
13///
14/// ```
15/// use postgrest_parser::parser::parse_json_body;
16///
17/// let body = r#"{"name": "Alice", "age": 30}"#;
18/// let value = parse_json_body(body).unwrap();
19/// assert!(value.is_object());
20/// ```
21pub fn parse_json_body(body: &str) -> Result<Value, Error> {
22    serde_json::from_str(body).map_err(|e| {
23        Error::Parse(ParseError::InvalidJsonBody(format!(
24            "Failed to parse JSON body: {}",
25            e
26        )))
27    })
28}
29
30/// Validates and converts a JSON value into InsertValues
31///
32/// Supports both single object and array of objects.
33///
34/// # Arguments
35///
36/// * `value` - Parsed JSON value to validate
37///
38/// # Examples
39///
40/// ```
41/// use postgrest_parser::parser::{parse_json_body, validate_insert_body};
42///
43/// // Single row
44/// let body = r#"{"name": "Alice", "age": 30}"#;
45/// let value = parse_json_body(body).unwrap();
46/// let insert_values = validate_insert_body(value).unwrap();
47///
48/// // Multiple rows
49/// let body = r#"[{"name": "Alice"}, {"name": "Bob"}]"#;
50/// let value = parse_json_body(body).unwrap();
51/// let insert_values = validate_insert_body(value).unwrap();
52/// ```
53pub fn validate_insert_body(value: Value) -> Result<InsertValues, Error> {
54    match value {
55        Value::Object(map) => {
56            if map.is_empty() {
57                return Err(Error::Parse(ParseError::InvalidInsertBody(
58                    "Insert body cannot be an empty object".to_string(),
59                )));
60            }
61            let mut hash_map = HashMap::new();
62            for (k, v) in map {
63                hash_map.insert(k, v);
64            }
65            Ok(InsertValues::Single(hash_map))
66        }
67        Value::Array(arr) => {
68            if arr.is_empty() {
69                return Err(Error::Parse(ParseError::InvalidInsertBody(
70                    "Insert body cannot be an empty array".to_string(),
71                )));
72            }
73
74            let mut rows = Vec::new();
75            for (idx, item) in arr.into_iter().enumerate() {
76                match item {
77                    Value::Object(map) => {
78                        if map.is_empty() {
79                            return Err(Error::Parse(ParseError::InvalidInsertBody(format!(
80                                "Row {} is an empty object",
81                                idx
82                            ))));
83                        }
84                        let mut hash_map = HashMap::new();
85                        for (k, v) in map {
86                            hash_map.insert(k, v);
87                        }
88                        rows.push(hash_map);
89                    }
90                    _ => {
91                        return Err(Error::Parse(ParseError::InvalidInsertBody(format!(
92                            "Row {} must be an object, got {:?}",
93                            idx, item
94                        ))));
95                    }
96                }
97            }
98
99            Ok(InsertValues::Bulk(rows))
100        }
101        _ => Err(Error::Parse(ParseError::InvalidInsertBody(
102            "Insert body must be an object or array of objects".to_string(),
103        ))),
104    }
105}
106
107/// Validates and converts a JSON value into a HashMap for UPDATE operations
108///
109/// # Arguments
110///
111/// * `value` - Parsed JSON value to validate
112///
113/// # Examples
114///
115/// ```
116/// use postgrest_parser::parser::{parse_json_body, validate_update_body};
117///
118/// let body = r#"{"status": "active", "updated_at": "2024-01-01"}"#;
119/// let value = parse_json_body(body).unwrap();
120/// let update_values = validate_update_body(value).unwrap();
121/// assert_eq!(update_values.len(), 2);
122/// ```
123pub fn validate_update_body(value: Value) -> Result<HashMap<String, Value>, Error> {
124    match value {
125        Value::Object(map) => {
126            if map.is_empty() {
127                return Err(Error::Parse(ParseError::EmptyUpdateBody));
128            }
129            let mut hash_map = HashMap::new();
130            for (k, v) in map {
131                hash_map.insert(k, v);
132            }
133            Ok(hash_map)
134        }
135        _ => Err(Error::Parse(ParseError::InvalidUpdateBody(
136            "Update body must be an object".to_string(),
137        ))),
138    }
139}
140
141#[cfg(test)]
142mod tests {
143    use super::*;
144
145    #[test]
146    fn test_parse_json_body_valid_object() {
147        let body = r#"{"name": "Alice", "age": 30}"#;
148        let result = parse_json_body(body);
149        assert!(result.is_ok());
150        let value = result.unwrap();
151        assert!(value.is_object());
152    }
153
154    #[test]
155    fn test_parse_json_body_valid_array() {
156        let body = r#"[{"name": "Alice"}, {"name": "Bob"}]"#;
157        let result = parse_json_body(body);
158        assert!(result.is_ok());
159        let value = result.unwrap();
160        assert!(value.is_array());
161    }
162
163    #[test]
164    fn test_parse_json_body_invalid_json() {
165        let body = r#"{"name": "Alice""#; // Missing closing brace
166        let result = parse_json_body(body);
167        assert!(result.is_err());
168    }
169
170    #[test]
171    fn test_validate_insert_body_single_object() {
172        let value = serde_json::json!({"name": "Alice", "age": 30});
173        let result = validate_insert_body(value);
174        assert!(result.is_ok());
175        let insert_values = result.unwrap();
176        assert_eq!(insert_values.len(), 1);
177    }
178
179    #[test]
180    fn test_validate_insert_body_empty_object() {
181        let value = serde_json::json!({});
182        let result = validate_insert_body(value);
183        assert!(result.is_err());
184        assert!(matches!(
185            result.unwrap_err(),
186            Error::Parse(ParseError::InvalidInsertBody(_))
187        ));
188    }
189
190    #[test]
191    fn test_validate_insert_body_array() {
192        let value = serde_json::json!([
193            {"name": "Alice", "age": 30},
194            {"name": "Bob", "age": 25}
195        ]);
196        let result = validate_insert_body(value);
197        assert!(result.is_ok());
198        let insert_values = result.unwrap();
199        assert_eq!(insert_values.len(), 2);
200    }
201
202    #[test]
203    fn test_validate_insert_body_empty_array() {
204        let value = serde_json::json!([]);
205        let result = validate_insert_body(value);
206        assert!(result.is_err());
207    }
208
209    #[test]
210    fn test_validate_insert_body_array_with_empty_object() {
211        let value = serde_json::json!([{"name": "Alice"}, {}]);
212        let result = validate_insert_body(value);
213        assert!(result.is_err());
214    }
215
216    #[test]
217    fn test_validate_insert_body_array_with_non_object() {
218        let value = serde_json::json!([{"name": "Alice"}, "invalid"]);
219        let result = validate_insert_body(value);
220        assert!(result.is_err());
221    }
222
223    #[test]
224    fn test_validate_insert_body_invalid_type() {
225        let value = serde_json::json!("string");
226        let result = validate_insert_body(value);
227        assert!(result.is_err());
228
229        let value = serde_json::json!(123);
230        let result = validate_insert_body(value);
231        assert!(result.is_err());
232
233        let value = serde_json::json!(true);
234        let result = validate_insert_body(value);
235        assert!(result.is_err());
236    }
237
238    #[test]
239    fn test_validate_update_body_valid() {
240        let value = serde_json::json!({"status": "active", "updated_at": "2024-01-01"});
241        let result = validate_update_body(value);
242        assert!(result.is_ok());
243        let update_values = result.unwrap();
244        assert_eq!(update_values.len(), 2);
245        assert!(update_values.contains_key("status"));
246        assert!(update_values.contains_key("updated_at"));
247    }
248
249    #[test]
250    fn test_validate_update_body_empty_object() {
251        let value = serde_json::json!({});
252        let result = validate_update_body(value);
253        assert!(result.is_err());
254        assert!(matches!(
255            result.unwrap_err(),
256            Error::Parse(ParseError::EmptyUpdateBody)
257        ));
258    }
259
260    #[test]
261    fn test_validate_update_body_invalid_type() {
262        let value = serde_json::json!([{"status": "active"}]);
263        let result = validate_update_body(value);
264        assert!(result.is_err());
265
266        let value = serde_json::json!("string");
267        let result = validate_update_body(value);
268        assert!(result.is_err());
269    }
270
271    #[test]
272    fn test_validate_update_body_nested_values() {
273        let value = serde_json::json!({
274            "user": {
275                "name": "Alice",
276                "age": 30
277            },
278            "metadata": ["tag1", "tag2"]
279        });
280        let result = validate_update_body(value);
281        assert!(result.is_ok());
282        let update_values = result.unwrap();
283        assert_eq!(update_values.len(), 2);
284    }
285
286    #[test]
287    fn test_bulk_insert_consistency() {
288        let value = serde_json::json!([
289            {"name": "Alice", "age": 30},
290            {"name": "Bob", "age": 25},
291            {"name": "Charlie", "age": 35}
292        ]);
293        let result = validate_insert_body(value);
294        assert!(result.is_ok());
295        let insert_values = result.unwrap();
296
297        match insert_values {
298            InsertValues::Bulk(rows) => {
299                assert_eq!(rows.len(), 3);
300                for row in &rows {
301                    assert!(row.contains_key("name"));
302                    assert!(row.contains_key("age"));
303                }
304            }
305            _ => panic!("Expected Bulk insert"),
306        }
307    }
308}