odatav4_parser/renderers/
sqlite.rs1use crate::ast::QueryOptions;
2use crate::renderers::{filter::FilterRenderer, RenderedQuery, SqlRenderer};
3use std::collections::HashMap;
4
5pub struct SqliteRenderer;
7
8impl SqliteRenderer {
9 pub fn new() -> Self {
10 Self
11 }
12}
13
14impl Default for SqliteRenderer {
15 fn default() -> Self {
16 Self::new()
17 }
18}
19
20impl FilterRenderer for SqliteRenderer {
21 fn quote_identifier(&mut self, ident: &str) -> String {
22 format!("\"{}\"", ident)
23 }
24}
25
26impl SqlRenderer for SqliteRenderer {
27 fn render(&mut self, table_name: &str, options: &QueryOptions) -> RenderedQuery {
28 let mut parts = Vec::new();
29
30 parts.push("SELECT".to_string());
32
33 if let Some(ref fields) = options.select {
35 let field_list = fields
36 .iter()
37 .map(|f| self.quote_identifier(f))
38 .collect::<Vec<_>>()
39 .join(", ");
40 parts.push(field_list);
41 } else {
42 parts.push("*".to_string());
43 }
44
45 parts.push("FROM".to_string());
47 parts.push(self.quote_identifier(table_name));
48
49 if let Some(ref expand_fields) = options.expand {
51 let expand_list = expand_fields
52 .iter()
53 .map(|item| item.field.clone())
54 .collect::<Vec<_>>()
55 .join(", ");
56 parts.push(format!(
57 "/* TODO: JOIN {} */",
58 expand_list
59 ));
60 }
61
62 if let Some(ref filter) = options.filter {
64 parts.push("WHERE".to_string());
65 parts.push(self.render_filter(filter));
66 }
67
68 if let Some(ref groupby_fields) = options.groupby {
70 let groupby_list = groupby_fields
71 .iter()
72 .map(|f| self.quote_identifier(f))
73 .collect::<Vec<_>>()
74 .join(", ");
75 parts.push(format!("GROUP BY {}", groupby_list));
76 }
77
78 if let Some(ref orderby_items) = options.orderby {
80 let orderby_list = orderby_items
81 .iter()
82 .map(|item| {
83 let dir = match item.direction {
84 crate::ast::SortDirection::Asc => "ASC",
85 crate::ast::SortDirection::Desc => "DESC",
86 };
87 format!("{} {}", self.quote_identifier(&item.field), dir)
88 })
89 .collect::<Vec<_>>()
90 .join(", ");
91 parts.push(format!("ORDER BY {}", orderby_list));
92 }
93
94 if let Some(top) = options.top {
96 parts.push(format!("LIMIT {}", top));
97 }
98
99 if let Some(skip) = options.skip {
101 parts.push(format!("OFFSET {}", skip));
102 }
103
104 RenderedQuery::new(parts.join(" "), HashMap::new())
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn test_sqlite_select_only() {
114 let mut renderer = SqliteRenderer::new();
115 let mut options = QueryOptions::new();
116 options.select = Some(vec!["id".to_string(), "name".to_string()]);
117
118 let query = renderer.render("users", &options);
119 assert_eq!(query.sql, "SELECT \"id\", \"name\" FROM \"users\"");
120 }
121
122 #[test]
123 fn test_sqlite_limit() {
124 let mut renderer = SqliteRenderer::new();
125 let mut options = QueryOptions::new();
126 options.top = Some(10);
127
128 let query = renderer.render("users", &options);
129 assert_eq!(query.sql, "SELECT * FROM \"users\" LIMIT 10");
130 }
131
132 #[test]
133 fn test_sqlite_offset() {
134 let mut renderer = SqliteRenderer::new();
135 let mut options = QueryOptions::new();
136 options.skip = Some(20);
137
138 let query = renderer.render("users", &options);
139 assert_eq!(query.sql, "SELECT * FROM \"users\" OFFSET 20");
140 }
141
142 #[test]
143 fn test_sqlite_combined() {
144 let mut renderer = SqliteRenderer::new();
145 let mut options = QueryOptions::new();
146 options.select = Some(vec!["id".to_string(), "name".to_string()]);
147 options.top = Some(10);
148 options.skip = Some(20);
149
150 let query = renderer.render("users", &options);
151 assert_eq!(
152 query.sql,
153 "SELECT \"id\", \"name\" FROM \"users\" LIMIT 10 OFFSET 20"
154 );
155 }
156}