inquerest/lib.rs
1#![deny(warnings)]
2//! Inquerest can parse complex url query into a SQL abstract syntax tree.
3//!
4//! Example this url:
5//! ```no_run,ignore
6//! /person?age=lt.42&(student=eq.true|gender=eq.'M')&group_by=sum(age),grade,gender&having=min(age)=gt.42&order_by=age.desc,height.asc&page=20&page_size=100
7//! ```
8//! will be parsed into:
9//!
10//! ```rust,ignore
11//! Select {
12//! from_table: FromTable {
13//! from: Table {
14//! name: "person",
15//! },
16//! join: None,
17//! },
18//! filter: Some(
19//! BinaryOperation(
20//! BinaryOperation {
21//! left: BinaryOperation(
22//! BinaryOperation {
23//! left: Column(
24//! Column {
25//! name: "age",
26//! },
27//! ),
28//! operator: Lt,
29//! right: Value(
30//! Number(
31//! 42.0,
32//! ),
33//! ),
34//! },
35//! ),
36//! operator: And,
37//! right: Nested(
38//! BinaryOperation(
39//! BinaryOperation {
40//! left: BinaryOperation(
41//! BinaryOperation {
42//! left: Column(
43//! Column {
44//! name: "student",
45//! },
46//! ),
47//! operator: Eq,
48//! right: Value(
49//! Bool(
50//! true,
51//! ),
52//! ),
53//! },
54//! ),
55//! operator: Or,
56//! right: BinaryOperation(
57//! BinaryOperation {
58//! left: Column(
59//! Column {
60//! name: "gender",
61//! },
62//! ),
63//! operator: Eq,
64//! right: Value(
65//! String(
66//! "M",
67//! ),
68//! ),
69//! },
70//! ),
71//! },
72//! ),
73//! ),
74//! },
75//! ),
76//! ),
77//! group_by: Some(
78//! [
79//! Function(
80//! Function {
81//! name: "sum",
82//! params: [
83//! Column(
84//! Column {
85//! name: "age",
86//! },
87//! ),
88//! ],
89//! },
90//! ),
91//! Column(
92//! Column {
93//! name: "grade",
94//! },
95//! ),
96//! Column(
97//! Column {
98//! name: "gender",
99//! },
100//! ),
101//! ],
102//! ),
103//! having: Some(
104//! BinaryOperation(
105//! BinaryOperation {
106//! left: Function(
107//! Function {
108//! name: "min",
109//! params: [
110//! Column(
111//! Column {
112//! name: "age",
113//! },
114//! ),
115//! ],
116//! },
117//! ),
118//! operator: Gt,
119//! right: Value(
120//! Number(
121//! 42.0,
122//! ),
123//! ),
124//! },
125//! ),
126//! ),
127//! projection: None,
128//! order_by: Some(
129//! [
130//! Order {
131//! expr: Column(
132//! Column {
133//! name: "age",
134//! },
135//! ),
136//! direction: Some(
137//! Desc,
138//! ),
139//! },
140//! Order {
141//! expr: Column(
142//! Column {
143//! name: "height",
144//! },
145//! ),
146//! direction: Some(
147//! Asc,
148//! ),
149//! },
150//! ],
151//! ),
152//! range: Some(
153//! Page(
154//! Page {
155//! page: 20,
156//! page_size: 100,
157//! },
158//! ),
159//! ),
160//! }
161//! ```
162//! Which translate to the sql statement:
163//! ```sql
164//! SELECT * FROM person WHERE age < 42 AND (student = true OR gender = 'M') GROUP BY sum(age), grade, gender HAVING min(age) > 42 ORDER BY age DESC, height ASC LIMIT 100 OFFSET 1900 ROWS
165//! ```
166//! Note: However, you don't want to convert to the sql statement directly to avoid sql injection
167//! attack. You need to validate the tables and columns if it is allowed to be accessed by the
168//! user. You also need to extract the values yourself and supply it as a parameterized value into
169//! your ORM.
170//!
171//! #### Please support this project:
172//! [](https://www.patreon.com/ivanceras)
173pub use restq;
174
175pub use restq::{
176 ast::{Expr, Select},
177 parser::filter_expr,
178 to_chars, Error,
179};
180
181/// Parse a path and query in a url to a Select AST
182/// Example:
183/// ```rust
184/// use inquerest::*;
185///
186/// let url = "/person?age=lt.42&(student=eq.true|gender=eq.'M')&group_by=sum(age),grade,gender&having=min(age)=gt.42&order_by=age.desc,height.asc&page=20&page_size=100";
187/// let query = inquerest::parse_query(url);
188/// println!("query: {:#?}", query);
189/// println!(
190/// "sql query: {}",
191/// query.unwrap().into_sql_statement(None).unwrap().to_string()
192/// );
193/// ```
194pub fn parse_query(input: &str) -> Result<Select, Error> {
195 let input_chars = to_chars(input);
196 restq::parse_select_chars(&input_chars)
197}
198
199/// Parse the query in a url to an Expression
200///
201/// Example:
202/// ```rust
203/// use inquerest::*;
204///
205/// let filter = "age=lt.42&(student=eq.true|gender=eq.'M')&group_by=sum(age),grade,gender&having=min(age)=gt.42&order_by=age.desc,height.asc&page=20&page_size=100";
206/// let result = parse_filter(filter);
207/// println!("filter_only: {:#?}", result);
208/// ```
209pub fn parse_filter(input: &str) -> Result<Expr, Error> {
210 let input_chars = to_chars(input);
211 parse_filter_chars(&input_chars)
212}
213
214fn parse_filter_chars(input: &[char]) -> Result<Expr, Error> {
215 Ok(filter_expr().parse(input)?)
216}