doublify_toolkit/filtering/
mod.rs

1// The MIT License (MIT)
2//
3// Copyright (c) 2017 Doublify Technologies
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21// THE SOFTWARE.
22mod parser;
23mod scanner;
24mod tokenizer;
25
26pub use filtering::parser::{Expression, InExpression, Literal, OrExpression, VariableDeclaration,
27                            VariableDeclarationKind, parse};
28pub use filtering::scanner::{Kind, Token, scan};
29pub use filtering::tokenizer::tokenize;
30
31use std::collections::HashMap;
32
33/// Type of operation
34#[derive(Debug, PartialEq)]
35pub enum Operation {
36  /// =
37  Equal,
38  /// {}
39  Or,
40  /// ()
41  In,
42}
43
44/// Filter
45#[derive(Debug, PartialEq)]
46pub struct Filter {
47  /// Type of operation
48  pub operation: Operation,
49  /// Values
50  pub bindings: Vec<Literal>,
51}
52
53/// Query
54#[derive(Debug, PartialEq)]
55pub struct Query {
56  /// Map of filters
57  pub bindings: HashMap<String, Filter>,
58}
59
60/// Traverses identifier
61///
62/// Checks if identifier is reserved keyword (`IsKeyword` or `NotKeyword`)
63/// and returns identifier in initializer or identifier name.
64fn traverse_identifier(name: &Literal, children: &Option<Box<Expression>>) -> String {
65  let default = &String::new();
66  let new_name = if let Some(box Expression::Literal(Literal::Identifier(ref name))) = *children {
67    name
68  } else if let Literal::Identifier(ref name) = *name {
69    name
70  } else {
71    default
72  };
73
74  new_name.to_owned()
75}
76
77/// Traverses children of array-like expression (`InExpression` or `OrExpression`)
78fn traverse_children(filter: &mut Filter, children: &Vec<Box<Expression>>) {
79  for child in children {
80    match *child {
81      box Expression::Literal(ref binding) => filter.bindings.push(binding.to_owned()),
82      _ => {}
83    }
84  }
85}
86
87/// Traverses variable declaration
88fn traverse_variable_declaration(VariableDeclaration { ref mut kind, ref name, ref mut children }: VariableDeclaration) -> (String, Filter){
89  let new_name = traverse_identifier(name, children);
90
91  let mut filter = Filter {
92    operation: Operation::Equal,
93    bindings: vec![],
94  };
95
96  children
97    .take()
98    .map(
99      |expr| match expr {
100        box Expression::OrExpression(OrExpression { ref children }) => {
101          filter.operation = Operation::Or;
102          traverse_children(&mut filter, children);
103        }
104        box Expression::InExpression(InExpression { ref children }) => {
105          filter.operation = Operation::In;
106          traverse_children(&mut filter, children);
107        }
108        box Expression::Literal(binding) => {
109          use self::VariableDeclarationKind::*;
110
111          let traverse = |kind| {
112            Literal::Boolean(
113              match kind {
114                IsKeyword => true,
115                NotKeyword => false,
116              },
117            )
118          };
119
120          filter
121            .bindings
122            .push(kind.take().map_or(binding, traverse))
123        }
124        _ => {}
125      },
126    );
127
128  (new_name, filter)
129}
130
131/// Parses query
132pub fn parse_query(raw_query: &str) -> Query {
133  let tokens = tokenize(raw_query);
134  let source = parse(tokens);
135  let mut bindings: HashMap<String, Filter> = HashMap::new();
136
137  for node in source.body {
138    if let Expression::VariableDeclaration(variable_declaration) = *node {
139      let (name, filter) = traverse_variable_declaration(variable_declaration);
140
141      bindings.insert(name, filter);
142    }
143  }
144
145  Query { bindings: bindings }
146}