#查询语言 #查询解析器 #用户输入 #语言 #字符串 #SQL解析器 #解析器

fexpr

简单的过滤器查询语言解析器,让您可以从用户输入安全地构建SQL、Elasticsearch等查询。

3个版本

0.1.2 2024年8月16日
0.1.1 2024年2月10日
0.1.0 2024年2月10日

#994 in 解析器实现

Download history 2/week @ 2024-06-30 10/week @ 2024-07-07 28/week @ 2024-07-28 122/week @ 2024-08-11

每月150次下载

BSD-3-Clause

67KB
2K SLoC

fexpr 最新版本

用Rust重写Go fexpr

fexpr是一个过滤器查询语言解析器,它生成易于工作的AST结构,以便您可以从用户输入安全地创建SQL、Elasticsearch等查询。

换句话说,将字符串"id > 1"转换为结构体[{&& {{identifier id} > {number 1}}}]

支持括号和各种条件表达式运算符(见语法)。

示例用法

cargo add fexpr
fn main() {
    let result = fexpr::parse("id=123 && status='active'");
    if let Ok(result) = result {
        println!("{}", result)
    }
}

// Output:
// [{&& {{identifier id} = {number 123}}} {&& {{identifier status} = {text active}}}]

注意,每个解析的表达式语句都包含一个连接/并集运算符(&&||),以便可以在小段上消耗结果,而无需依赖于分组/嵌套上下文。

语法

fexpr语法类似于SQL的WHERE表达式语法。它识别几种标记类型(标识符、数字、引号文本、表达式运算符、空格等)。

您可以在scanner.rs中找到所有支持的标记。

运算符

  • = 等于运算符(例如a=b
  • != 不等于运算符(例如a!=b
  • > 大于运算符(例如a>b
  • >= 大于或等于运算符(例如a>=b
  • < 小于或等于运算符(例如:a<b
  • <= 小于或等于运算符(例如:a<=b
  • ~ 类似/包含运算符(例如:a~b
  • !~ 非 类似/包含运算符(例如:a!~b
  • ?= 数组/任意等于运算符(例如:a?=b
  • ?!= 数组/任意不等于运算符(例如:a?!=b
  • ?> 数组/任意大于运算符(例如:a?>b
  • ?>= 数组/任意大于等于运算符(例如:a?>=b
  • ?< 数组/任意小于运算符(例如:a?<b
  • ?<= 数组/任意小于等于运算符(例如:a?<=b
  • ?~ 数组/任意 类似/包含运算符(例如:a?~b
  • ?!~ 数组/任意 非 类似/包含运算符(例如:a?!~b
  • && AND 连接运算符(例如:a=b && c=d
  • || OR 连接运算符(例如:a=b || c=d
  • () 括号(例如:(a=1 && b=2) || (a=3 && b=4)

数字

数字标记可以是任何整数或小数。

示例12310.50-14

标识符

标识符标记是以下字符开头的字面量:字母、_@#,并且可以包含任意数量的字母、数字、.(通常用作分隔符)或 :(通常用作修饰符)字符。

示例ida.b.cfield123@request.methodauthor.name:length

引文文本

文本标记是任何被 '" 引号包裹的字面量。

示例'Lorem ipsum dolor 123!'"escaped \"word\"""mixed 'quotes' are fine"

注释

注释标记是任何以 // 开头的单行文本字面量。与空白符类似,注释会被 fexpr::parse() 忽略。

示例// test

仅使用扫描器

标记化器(又称 fexpr::Scanner)可以在没有解析器状态机的情况下使用,这样您就可以编写自己的自定义标记处理程序。

use std::io::BufReader;

fn main() {
    let s = fexpr::Scanner::new(BufReader::new("id > 123".as_bytes()));

    if let Ok(mut s) = s {
        loop {
            let t = s.scan();

            if let Err(_) = t {
                break;
            }

            if let Ok(t) = t {
                if matches!(t, fexpr::Token::Eof(_)) {
                    break;
                }

                println!("{t}")
            }
        }
    }
}

// Output:
// {identifier id}
// {whitespace  }
// {sign >}
// {whitespace  }
// {number 123}

依赖项

~2.1–3MB
~53K SLoC