Rust数据查询引擎Trustfall核心库trustfall_core的使用,支持高效灵活的数据查询与处理

Rust数据查询引擎Trustfall核心库trustfall_core的使用,支持高效灵活的数据查询与处理

Trustfall是一个可以查询各类数据源的查询引擎,从API和数据库到磁盘上的各种文件,甚至AI模型都可以查询。

浏览器中尝试Trustfall

Trustfall Playground支持对以下公共数据源运行查询:

  • HackerNews REST APIs
  • 顶级Rust库的rustdoc JSON

例如,可以运行查询:“哪些GitHub或Twitter用户正在评论关于OpenAI的故事?”

10分钟技术演讲+演示

Trustfall曾在HYTRADBOI 2022会议上进行了"如何查询(几乎)一切"的技术演讲。

Terminal recording of running cargo run --release -- query example_queries/actions_in_repos_with_min_10_hn_pts.ron in the demo-hytradboi demo project. The system returns the first 20 results of the query in 6.36 seconds.

演示从演讲中展示跨API查询的执行:“哪些GitHub Actions被用在HackerNews首页上得分≥10的项目中?”

演示执行了以下跨HackerNews和GitHub API以及YAML格式的GitHub仓库工作流文件的查询:

{
  HackerNewsTop(max: 200) {
    ... on HackerNewsStory {
      hn_score: score @filter(op: ">=", value: ["$min_score"]) @output

      link {
        ... on GitHubRepository {
          repo_url: url @output

          workflows {
            workflow: name @output
            workflow_path: path @output

            jobs {
              job: name @output

              step {
                ... on GitHubActionsImportedStep {
                  step: name @output
                  action: uses @output
                }
              }
            }
          }
        }
      }
    }
  }
}

查询真实世界数据的示例

  • HackerNews APIs,包括查询语言概述和查询REST API的示例
  • RSS/Atom feeds,展示如何查询结构化数据如RSS/Atom feeds
  • 机场天气数据(METAR),展示如何查询航空天气报告的CSV数据

Trustfall还支持cargo-semver-checks语义版本检查工具。

在新数据源上使用Trustfall

最简单的方法是实现BasicAdapter trait。

Python绑定可用,并在引擎每次更改时自动构建;最新的版本可以下载。Python入门指南即将发布。

目录注册表

  • trustfall是外观crate。这是使用Trustfall的首选方式。
  • trustfall_core包含查询引擎内部
  • trustfall_derive定义简化数据源插入的宏
  • pytrustfall包含Trustfall的Python绑定
  • trustfall_wasm是Trustfall的WASM构建
  • trustfall_filetests_macros是一个用于生成由文件定义的测试案例的过程宏
  • experiments包含各种实验性项目

完整示例代码

以下是一个使用trustfall_core的完整示例:

use trustfall_core::{ir::FieldValue, interpreter::BasicAdapter, schema::Schema};

// 1. 定义你的数据源适配器
struct MyAdapter;

impl BasicAdapter for MyAdapter {
    type Vertex = String;
    
    fn resolve_starting_vertices(
        &self,
        edge_name: &str,
        _parameters: &[(&str, FieldValue)],
    ) -> Vec<Self::Vertex> {
        match edge_name {
            "Root" => vec!["root_node".to_string()],
            _ => vec![],
        }
    }
    
    fn resolve_property(
        &self,
        context: &Self::Vertex,
        type_name: &str,
        property_name: &str,
    ) -> FieldValue {
        match (context.as_str(), type_name, property_name) {
            ("root_node", "Root", "name") => FieldValue::String("Root Node".to_string()),
            _ => FieldValue::Null,
        }
    }
    
    fn resolve_neighbors(
        &self,
        context: &Self::Vertex,
        type_name: &str,
        edge_name: &str,
    ) -> Vec<Self::Vertex> {
        match (context.as_str(), type_name, edge_name) {
            ("root_node", "Root", "children") => vec!["child1".to_string(), "child2".to_string()],
            _ => vec![],
        }
    }
}

// 2. 定义你的GraphQL schema
const SCHEMA: &str = r#"
type Root {
    name: String
    children: [Child]
}

type Child {
    name: String
}

schema {
    query: Root
}
"#;

fn main() {
    // 3. 创建schema
    let schema = Schema::parse(SCHEMA).expect("valid schema");
    
    // 4. 创建适配器实例
    let adapter = MyAdapter;
    
    // 5. 准备查询
    let query = r#"
    {
        Root {
            name @output
            children {
                name @output
            }
        }
    }
    "#;
    
    // 6. 执行查询
    let results = trustfall_core::execute_query(&schema, &adapter, query)
        .expect("valid query execution");
    
    // 7. 处理结果
    for result in results {
        println!("Result: {:?}", result);
    }
}

这个示例展示了如何:

  1. 创建一个基本适配器实现BasicAdapter trait
  2. 定义GraphQL schema
  3. 解析schema
  4. 创建适配器实例
  5. 准备查询
  6. 执行查询
  7. 处理结果

Trustfall提供了灵活的方式来查询各种数据源,同时保持高效的性能。通过实现适配器接口,你可以轻松地将Trustfall集成到现有的数据系统中。


1 回复

以下是基于您提供的Trustfall核心库使用指南内容的完整示例demo:

// 1. 添加依赖到Cargo.toml
/*
[dependencies]
trustfall_core = "0.12.0"
*/

use trustfall_core::{
    schema::Schema, 
    Adapter, 
    AdapterContext, 
    EdgeParameters, 
    execute_query, 
    QueryContext,
    VertexIterator
};

// 2. 定义数据模型和顶点类型
#[derive(Debug)]
struct Person {
    name: String,
    age: Option<i64>,
    friends: Vec<Person>,
}

// 3. 实现适配器
struct PersonAdapter;

impl Adapter for PersonAdapter {
    type Vertex = Person;

    fn resolve_starting_vertices(
        &self,
        edge_name: &str,
        _parameters: &EdgeParameters,
        _ctx: &AdapterContext,
    ) -> VertexIterator<Self::Vertex> {
        // 模拟数据源
        let people = vec![
            Person {
                name: "Alice".to_string(),
                age: Some(25),
                friends: vec![
                    Person {
                        name: "Bob".to_string(),
                        age: Some(30),
                        friends: vec![],
                    },
                    Person {
                        name: "Charlie".to_string(),
                        age: Some(22),
                        friends: vec![],
                    },
                ],
            },
            Person {
                name: "John".to_string(),
                age: Some(35),
                friends: vec![
                    Person {
                        name: "Jane".to_string(),
                        age: Some(28),
                        friends: vec![],
                    },
                ],
            },
        ];
        
        // 只返回Person类型的顶点
        if edge_name == "Person" {
            Box::new(people.into_iter())
        } else {
            Box::new(std::iter::empty())
        }
    }
}

fn main() {
    // 定义Schema
    let schema = Schema::parse(
        r#"
        type Person {
            name: String!
            age: Int
            friends: [Person!]!
        }
        "#,
    ).expect("Valid schema");

    // 执行基础查询
    let query = r#"
    {
        Person {
            name @output
            age @output
            friends {
                name @output
            }
        }
    }
    "#;

    let results = execute_query::<PersonAdapter>(
        &schema,
        PersonAdapter,
        query,
        std::collections::HashMap::new(),
        QueryContext::default(),
    ).expect("Query failed");

    println!("基础查询结果: {:?}", results);

    // 执行参数化查询
    let param_query = r#"
    query FindPerson($name: String!) {
        Person {
            name @filter(op: "=", value: ["$name"])
            age @output
            friends {
                name @output
            }
        }
    }
    "#;

    let variables = std::collections::HashMap::from([
        ("name".to_string(), "Alice".into())
    ]);

    let param_results = execute_query::<PersonAdapter>(
        &schema,
        PersonAdapter,
        param_query,
        variables,
        QueryContext::default(),
    ).expect("Parameterized query failed");

    println!("参数化查询结果: {:?}", param_results);

    // 执行递归查询
    let recurse_query = r#"
    {
        Person {
            name @output
            friends @recurse(depth: 2) {
                name @output
            }
        }
    }
    "#;

    let recurse_results = execute_query::<PersonAdapter>(
        &schema,
        PersonAdapter,
        recurse_query,
        std::collections::HashMap::new(),
        QueryContext::default(),
    ).expect("Recursive query failed");

    println!("递归查询结果: {:?}", recurse_results);
}

这个完整示例展示了:

  1. 定义Person数据模型和顶点类型
  2. 实现PersonAdapter适配器连接模拟数据
  3. 执行三种不同类型的查询:
    • 基础查询:获取所有人的姓名、年龄和朋友列表
    • 参数化查询:按姓名过滤查找特定人员
    • 递归查询:递归查找朋友关系(深度为2)

您可以根据实际需求修改Person数据结构和适配器实现来连接真实数据源。

回到顶部