You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust中如何替换插值分隔符以嵌入EdgeQL查询?

在Rust中嵌入EdgeQL时避免花括号转义的编译时方案

1. 自定义编译时Proc宏(支持${}插值)

你可以实现一个自定义proc宏,比如edgeql!,让它识别${var}风格的插值标记,自动处理EdgeQL原生花括号的转义,且逻辑在编译时完成。

首先在Cargo.toml中添加依赖:

[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "2.0", features = ["full"] }

[lib]
proc-macro = true

然后编写宏实现:

use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::{parse::Parse, parse_macro_input, LitStr, Token};

struct EdgeqlQuery {
    query: LitStr,
    args: Vec<syn::Expr>,
}

impl Parse for EdgeqlQuery {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        let query = input.parse::<LitStr>()?;
        let mut args = Vec::new();
        while !input.is_empty() {
            input.parse::<Token![,]>()?;
            args.push(input.parse::<syn::Expr>()?);
        }
        Ok(Self { query, args })
    }
}

#[proc_macro]
pub fn edgeql(input: TokenStream) -> TokenStream {
    let EdgeqlQuery { query, args } = parse_macro_input!(input as EdgeqlQuery);
    let query_str = query.value();
    
    // 替换${var}为{},保留原生EdgeQL花括号
    let formatted_query = query_str.replace("${", "{");
    
    // 生成format!调用代码
    let expanded = quote! {
        format!(#formatted_query, #(#args),*)
    };
    expanded.into()
}

使用示例:

use your_crate::edgeql;

fn main() {
    let user_id = 123;
    let query = edgeql!(r#"
        SELECT User {{
            name,
            posts := (SELECT Post WHERE author.id = ${user_id})
        }}
    "#, user_id);
    println!("{}", query);
}

这个宏会在编译时完成插值标记替换,原生EdgeQL花括号无需转义。

2. 使用EdgeQL官方库的编译时宏

edgeql-rs库提供的query!宏原生支持编译时查询插值,完全不需要转义EdgeQL中的花括号,还能做语法和类型检查。

在Cargo.toml添加依赖:

[dependencies]
edgeql = "0.10"

使用示例:

use edgeql::query;

#[tokio::main]
async fn main() -> Result<(), edgeql::Error> {
    let client = edgeql::Client::new().await?;
    let user_id = 123;
    
    // 直接写EdgeQL原生语法,用$user_id做插值
    let users = query!(r#"
        SELECT User {{
            name,
            posts := (SELECT Post WHERE author.id = $user_id)
        }}
    "#, user_id).fetch_all(&client).await?;
    
    for user in users {
        println!("User: {}", user.name);
    }
    Ok(())
}

这是最推荐的方案,编译时就能校验查询合法性和参数类型匹配。

3. 利用EdgeQL命名参数(无需宏)

如果不想依赖proc宏,可直接用EdgeQL的命名参数特性,查询写为原始字符串字面量,执行时传入参数映射:

use edgeql::Client;

#[tokio::main]
async fn main() -> Result<(), edgeql::Error> {
    let client = Client::new().await?;
    let user_id = 123;
    
    let query = r#"
        SELECT User {{
            name,
            posts := (SELECT Post WHERE author.id := <int64>$user_id)
        }}
    "#;
    
    let users = client.query(query, &[("user_id", &user_id)]).await?;
    Ok(())
}

这种方式不用转义花括号,参数通过命名映射传递,虽无编译时查询检查,但能解决转义麻烦。

内容的提问来源于stack exchange,提问作者FoxPro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 13:16:00