1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4#![allow(deref_nullptr)]
5
6include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
7include!(concat!(env!("OUT_DIR"), "/pg_query.rs"));
8
9use prost::Message;
11use std::ffi::{CStr, CString, NulError};
12use thiserror::Error;
13
14#[derive(Debug, Error)]
15pub enum Error {
16 #[error("Invalid statement format: {0}")]
17 Conversion(#[from] NulError),
18 #[error("Error decoding result: {0}")]
19 Decode(#[from] prost::DecodeError),
20 #[error("Invalid statement: {0}")]
21 Parse(std::string::String),
22}
23
24pub fn parseToJson(statement: &str) -> Result<std::string::String, Error> {
26 let input = CString::new(statement)?;
27 let result = unsafe { pg_query_parse(input.as_ptr()) };
28
29 let response = if !result.error.is_null() {
30 let message = unsafe { CStr::from_ptr((*result.error).message) }
31 .to_string_lossy()
32 .to_string();
33
34 Err(Error::Parse(message))
35 } else {
36 let parse_tree = unsafe { CStr::from_ptr(result.parse_tree) }
37 .to_string_lossy()
38 .to_string();
39
40 Ok(parse_tree)
41 };
42
43 unsafe { pg_query_free_parse_result(result) };
44
45 response
46}
47
48pub fn parseToProtobuf(statement: &str) -> Result<ParseResult, Error> {
50 let input = CString::new(statement)?;
51 let result = unsafe { pg_query_parse_protobuf(input.as_ptr()) };
52
53 let response = if !result.error.is_null() {
54 let message = unsafe { CStr::from_ptr((*result.error).message) }
55 .to_string_lossy()
56 .to_string();
57
58 Err(Error::Parse(message))
59 } else {
60 let data = unsafe {
61 std::slice::from_raw_parts(
62 result.parse_tree.data as *const u8,
63 result.parse_tree.len as usize,
64 )
65 };
66
67 ParseResult::decode(data).map_err(Error::Decode)
68 };
69
70 unsafe { pg_query_free_protobuf_parse_result(result) };
71
72 response
73}
74
75pub fn parse(statement: &str) -> Result<ParseResult, Error> {
77 parseToProtobuf(statement)
78}
79
80#[cfg(test)]
81mod test {
82 use super::*;
83
84 #[test]
89 fn parses_to_json() {
90 let json =
91 parseToJson("select * from items").expect("Error parsing valid statement into JSON");
92
93 let _map: serde_json::Map<std::string::String, serde_json::Value> =
94 serde_json::from_str(&json).expect("Error parsing response into JSON Object");
95 }
96
97 #[test]
98 fn parses_to_proto() {
99 let _ = parseToProtobuf("select null")
100 .expect("Error parsing statement 'select null' into Protobuf");
101
102 let _ = parseToProtobuf("select ''")
103 .expect("Error parsing statement 'select ''' into Protobuf");
104
105 let _ = parseToProtobuf("checkpoint")
106 .expect("Error parsing statement 'checkpoint' into Protobuf");
107
108 let _ = parseToProtobuf("select from items")
109 .expect("Error parsing statement 'select from items' into Protobuf");
110
111 let proto =
112 parseToProtobuf("select *").expect("Error parsing statement 'select *' into Protobuf");
113
114 assert_eq!(
115 proto.stmts.len(),
116 1,
117 "Failed to parse correct number of statements"
118 )
119 }
120}