mirror of
https://github.com/meilisearch/MeiliSearch
synced 2024-11-29 08:14:26 +01:00
logic skeleton for filter and parser
This commit is contained in:
parent
6db6b40659
commit
66568a913c
1992
Cargo.lock
generated
1992
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,7 @@ members = [
|
||||
"meilisearch-schema",
|
||||
"meilisearch-tokenizer",
|
||||
"meilisearch-types",
|
||||
"meilisearch-filters",
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
|
15
meilisearch-filters/Cargo.toml
Normal file
15
meilisearch-filters/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "meilisearch-filters"
|
||||
version = "0.9.0"
|
||||
authors = ["mposmta <postma.marin@protonmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
lazy_static = "1.4.0"
|
||||
meilisearch-core = { path = "../meilisearch-core", version = "0.9.0" }
|
||||
pest = "2.0"
|
||||
pest_derive = "2.0"
|
||||
heed = "0.6.1"
|
||||
|
23
meilisearch-filters/src/filter.rs
Normal file
23
meilisearch-filters/src/filter.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use crate::parser::Operation;
|
||||
use meilisearch_core::{DocumentId, Schema, MainT };
|
||||
use heed::RoTxn;
|
||||
|
||||
|
||||
pub struct Filter<'r> {
|
||||
reader: &'r RoTxn<MainT>,
|
||||
operation: Box<Operation>,
|
||||
}
|
||||
|
||||
impl<'r> Filter<'r> {
|
||||
pub fn new<T: AsRef<str>>(expr: T, schema: &Schema, reader: &'r RoTxn<MainT>) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let operation = Box::new(Operation::parse_with_schema(expr, schema)?);
|
||||
Ok( Self {
|
||||
reader,
|
||||
operation,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn test(&self, _document_id: &DocumentId) -> Result<bool, Box<dyn std::error::Error>> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
6
meilisearch-filters/src/lib.rs
Normal file
6
meilisearch-filters/src/lib.rs
Normal file
@ -0,0 +1,6 @@
|
||||
extern crate pest;
|
||||
#[macro_use]
|
||||
extern crate pest_derive;
|
||||
|
||||
mod parser;
|
||||
pub mod filter;
|
15
meilisearch-filters/src/parser/grammar.pest
Normal file
15
meilisearch-filters/src/parser/grammar.pest
Normal file
@ -0,0 +1,15 @@
|
||||
key = @{ASCII_ALPHANUMERIC+}
|
||||
value = @{ASCII_ALPHANUMERIC*}
|
||||
|
||||
query = {key ~ ":" ~ value}
|
||||
|
||||
prgm = {SOI ~ expr ~ EOI}
|
||||
expr = _{ term ~ (operation ~ term)* }
|
||||
term = _{query | "(" ~ expr ~ ")" | not}
|
||||
operation = _{ and | or }
|
||||
and = {"AND"}
|
||||
or = {"OR"}
|
||||
|
||||
not = {"NOT" ~ term}
|
||||
|
||||
WHITESPACE = _{ " " }
|
18
meilisearch-filters/src/parser/mod.rs
Normal file
18
meilisearch-filters/src/parser/mod.rs
Normal file
@ -0,0 +1,18 @@
|
||||
pub mod operation;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use pest::prec_climber::{Operator, Assoc, PrecClimber};
|
||||
|
||||
pub use operation::Operation;
|
||||
|
||||
lazy_static! {
|
||||
static ref PREC_CLIMBER: PrecClimber<Rule> = {
|
||||
use Assoc::*;
|
||||
use Rule::*;
|
||||
pest::prec_climber::PrecClimber::new(vec![Operator::new(or, Left), Operator::new(and, Left)])
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[grammar = "parser/grammar.pest"]
|
||||
pub struct FilterParser;
|
100
meilisearch-filters/src/parser/operation.rs
Normal file
100
meilisearch-filters/src/parser/operation.rs
Normal file
@ -0,0 +1,100 @@
|
||||
use super::{FilterParser, Rule, PREC_CLIMBER};
|
||||
use pest::{
|
||||
iterators::{Pair, Pairs},
|
||||
Parser,
|
||||
};
|
||||
use std::convert::From;
|
||||
use std::fmt;
|
||||
use meilisearch_core::Schema;
|
||||
|
||||
pub enum Query {
|
||||
Contains { field: String, value: String },
|
||||
IsEqual { field: String, value: String },
|
||||
IsLower { field: String, value: String },
|
||||
}
|
||||
|
||||
impl fmt::Debug for Query {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Contains { field, value } => write!(f, "{}:{}", field, value),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Pair<'_, Rule>> for Query {
|
||||
fn from(item: Pair<Rule>) -> Self {
|
||||
let mut items = item.into_inner();
|
||||
let key = items.next().unwrap();
|
||||
// do additional parsing here and get the correct query type
|
||||
let value = items.next().unwrap();
|
||||
Self::Contains {
|
||||
field: key.as_str().to_owned(),
|
||||
value: value.as_str().to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Span(usize, usize);
|
||||
|
||||
impl Span {
|
||||
pub fn merge(&self, other: &Span) -> Self {
|
||||
let start = if self.0 > other.0 { other.0 } else { self.0 };
|
||||
|
||||
let end = if self.0 < other.0 { other.0 } else { self.0 };
|
||||
Span(start, end)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pest::Span<'_>> for Span {
|
||||
fn from(other: pest::Span<'_>) -> Self {
|
||||
Span(other.start(), other.end())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Operation {
|
||||
Query(Query, Span),
|
||||
Or(Box<Operation>, Box<Operation>, Span),
|
||||
And(Box<Operation>, Box<Operation>, Span),
|
||||
Not(Box<Operation>, Span),
|
||||
}
|
||||
|
||||
impl Operation {
|
||||
pub fn as_span<'a>(&'a self) -> &'a Span {
|
||||
use Operation::*;
|
||||
match self {
|
||||
Query(_, span) | Or(_, _, span) | And(_, _, span) | Not(_, span) => span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn eval(expression: Pairs<Rule>) -> Operation {
|
||||
PREC_CLIMBER.climb(
|
||||
expression,
|
||||
|pair: Pair<Rule>| {
|
||||
let span = Span::from(pair.as_span());
|
||||
match pair.as_rule() {
|
||||
Rule::query => Operation::Query(Query::from(pair), span),
|
||||
Rule::prgm => eval(pair.into_inner()),
|
||||
Rule::not => Operation::Not(Box::new(eval(pair.into_inner())), span),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
},
|
||||
|lhs: Operation, op: Pair<Rule>, rhs: Operation| {
|
||||
let span = lhs.as_span().merge(rhs.as_span());
|
||||
match op.as_rule() {
|
||||
Rule::or => Operation::Or(Box::new(lhs), Box::new(rhs), span),
|
||||
Rule::and => Operation::And(Box::new(lhs), Box::new(rhs), span),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
impl Operation {
|
||||
pub fn parse_with_schema<T: AsRef<str>>(_expr: T, _schema: &Schema) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user