A tool to compile SQL to Elasticsearch queries
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

compiler.rs 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. use serde_json::{json, Value};
  2. use std::fmt::{Display, Formatter};
  3. use crate::ast::{Field, KIdentifier, KValue, Select, Where};
  4. use crate::error::KappeError;
  5. #[derive(Debug, PartialEq)]
  6. pub struct Query {
  7. pub source: KIdentifier,
  8. pub body: Value,
  9. }
  10. impl Query {
  11. pub fn new(source: KIdentifier, body: Value) -> Self {
  12. Self { source, body }
  13. }
  14. }
  15. impl Display for Query {
  16. fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
  17. let header = format!("GET /{}/_search", self.source.name);
  18. let body = match serde_json::to_string_pretty(&self.body) {
  19. Ok(body) => body,
  20. Err(_) => return Err(std::fmt::Error {}),
  21. };
  22. write!(f, "{}\n{}", header, body)
  23. }
  24. }
  25. pub fn compile(expr: Select) -> Result<Query, KappeError> {
  26. let field_names: Vec<Value> = expr
  27. .fields
  28. .iter()
  29. .map(|f| match f {
  30. Field::Star => Value::String("*".to_string()),
  31. Field::Named(name) => Value::String(name.clone()),
  32. })
  33. .collect();
  34. let query = if let Some(where_clause) = expr.where_clause {
  35. compile_where_clause(where_clause)
  36. } else {
  37. json!({ "match_all":{} })
  38. };
  39. let body = json!({
  40. "query": query,
  41. "_source": Value::Array(field_names)
  42. });
  43. Ok(Query::new(expr.source, body))
  44. }
  45. pub fn compile_where_clause(where_clause: Where) -> Value {
  46. let terms: Vec<Value> = where_clause
  47. .predicates
  48. .iter()
  49. .map(|predicate| {
  50. let mut map = serde_json::Map::new();
  51. let key = predicate.left.name.clone();
  52. let value = compile_kvalue(&predicate.right);
  53. map.insert(key, value);
  54. json!({ "term": Value::Object(map) })
  55. })
  56. .collect();
  57. json!({
  58. "bool": {
  59. "filter": Value::Array(terms)
  60. }
  61. })
  62. }
  63. pub fn compile_kvalue(value: &KValue) -> Value {
  64. match value {
  65. KValue::Identifier(identifier) => Value::String(identifier.name.to_string()),
  66. KValue::Number(number) => {
  67. Value::Number(serde_json::Number::from_f64(number.value).unwrap())
  68. }
  69. KValue::String(string) => Value::String(string.value.to_string()),
  70. }
  71. }
  72. #[cfg(test)]
  73. mod tests {
  74. use super::*;
  75. use crate::lexer::scan;
  76. use crate::parser::parse;
  77. fn _compile(input: &str) -> Result<Query, KappeError> {
  78. let tokens = scan(input).unwrap();
  79. let select = parse(tokens).unwrap();
  80. compile(select)
  81. }
  82. #[test]
  83. fn it_compiles_a_simple_select() {
  84. assert_eq!(
  85. _compile("SELECT * FROM bar").unwrap(),
  86. Query::new(
  87. KIdentifier::new("bar"),
  88. json!({
  89. "query": {
  90. "match_all": {}
  91. },
  92. "_source": ["*"]
  93. })
  94. )
  95. )
  96. }
  97. #[test]
  98. fn it_compiles_a_select_with_specific_fields() {
  99. assert_eq!(
  100. _compile("SELECT foo FROM bar").unwrap(),
  101. Query::new(
  102. KIdentifier::new("bar"),
  103. json!({
  104. "query": {
  105. "match_all": {}
  106. },
  107. "_source": ["foo"]
  108. })
  109. )
  110. )
  111. }
  112. #[test]
  113. fn it_compiles_a_select_with_a_single_predicate_where_clause() {
  114. let mut map: serde_json::Map<String, Value> = serde_json::Map::new();
  115. map.insert("baz".to_string(), Value::String("quux".to_string()));
  116. assert_eq!(
  117. _compile("SELECT * FROM bar WHERE baz = \"quux\"").unwrap(),
  118. Query::new(
  119. KIdentifier::new("bar"),
  120. json!({
  121. "query": {
  122. "bool": {
  123. "filter": [
  124. json!({ "term": Value::Object(map) })
  125. ]
  126. }
  127. },
  128. "_source": ["*"]
  129. })
  130. )
  131. )
  132. }
  133. #[test]
  134. fn it_compiles_a_select_with_a_multiple_predicate_where_claus() {
  135. let mut map_one: serde_json::Map<String, Value> = serde_json::Map::new();
  136. map_one.insert("baz".to_string(), Value::String("quux".to_string()));
  137. let mut map_two: serde_json::Map<String, Value> = serde_json::Map::new();
  138. map_two.insert(
  139. "bop".to_string(),
  140. Value::Number(serde_json::Number::from_f64(5.0).unwrap()),
  141. );
  142. assert_eq!(
  143. _compile("SELECT * FROM bar WHERE baz = \"quux\", bop = 5").unwrap(),
  144. Query::new(
  145. KIdentifier::new("bar"),
  146. json!({
  147. "query": {
  148. "bool": {
  149. "filter": [
  150. json!({ "term": Value::Object(map_one) }),
  151. json!({ "term": Value::Object(map_two) }),
  152. ]
  153. }
  154. },
  155. "_source": ["*"]
  156. })
  157. )
  158. )
  159. }
  160. }