PRQL 官方语言绑定全解析:Supported / Unsupported / Nascent 三级生态与 prqlc 核心 API 实践指南
【免费下载链接】prqlPRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement项目地址: https://gitcode.com/gh_mirrors/pr/prql
导读
本文以 PRQL 仓库中 Bindings 索引文档 为骨架,系统梳理 PRQL 编译器prqlc面向多语言生态的绑定策略与治理标准:从 Supported(JavaScript、Python、R、Rust)、Unsupported(Java、Elixir、C)到 Nascent(.NET、PHP)的三级分类,到各绑定包的安装方式、核心函数签名、错误处理与编译选项,再到仓库统一的命名规范。读完本文,你将掌握每个绑定的真实用法、它们背后的编译管线(prql_to_pl→pl_to_rq→rq_to_sql),以及如何在你的项目里快速接入 PRQL。
一、绑定的三级生态:一张图看懂维护边界
PRQL 的编译器核心用 Rust 编写,为了让其他语言的使用者也能编译 PRQL 查询,官方维护了多个语言绑定。这些绑定并非一刀切,而是按成熟度分为三档,每档对应不同的维护承诺与 API 稳定性保证:
| 级别 | 要求 | 当前绑定 |
|---|---|---|
| Supported(受支持) | 有专门维护者;实现了核心编译函数;对这些函数有测试覆盖;已发布到该语言的标准包仓库;在 Taskfile.yaml 中有可引导开发环境的脚本;代码风格检查工具(linter / formatter)已接入 pre-commit 或 MegaLinter | JavaScript、Python、R、Rust |
| Unsupported(不受支持) | 功能可用,但不满足上述全部标准;编译器 API 变更不做门禁(gate);一旦失效会被降级为 Nascent | Java、Elixir、prqlc-c(C 绑定) |
| Nascent(萌芽期) | 仍在开发中,可能尚未完全可用 | .NET、PHP |
从 Bindings 索引文档 可以看到一个关键治理细节:Supported 级别的绑定大多位于主 PRQL 仓库中,任何对编译器 API 的改动都必须同步保证这些绑定兼容——"We gate any changes to the compiler's API on compatible changes to the bindings"。这意味着只要你的语言绑定处于 Supported 级,编译器升级时你的使用方式不会突然失效。而 Unsupported 级绑定则没有这道门禁,属于"能用但不保证"的状态,若损坏会被降级到 Nascent。
二、核心编译管线:所有绑定共享的同一套 API
无论哪个语言绑定,其背后调用的都是同一个 Rust 编译器prqlc。在 prqlc/prqlc/src/lib.rs 中可以找到绑定必须实现的五个核心函数(也即 Supported 绑定要求的 "core compile functions"):
| 函数 | 作用 | 源码位置 |
|---|---|---|
compile(prql, options) | 将 PRQL 查询直接编译为 SQL 字符串 | lib.rs#L189 |
prql_to_pl(prql) | 将 PRQL 解析为 PL AST(PipeLine AST) | lib.rs#L371 |
pl_to_rq(pl) | 将 PL 解析、降级为 RQ AST(Relational Query) | lib.rs#L383 |
rq_to_sql(rq, options) | 将 RQ AST 生成为最终 SQL | lib.rs#L399 |
pl_to_prql(pl) | 将 PL AST 重新格式化为 PRQL 文本(用于格式化/美化) | lib.rs#L404 |
因此,各语言绑定暴露的 API 高度一致:要么是"一把梭"的compile,要么是分段式流水线prql_to_pl/pl_to_rq/rq_to_sql,后者方便你介入中间环节做自定义处理(比如检查中间 AST、注入优化)。compile本质上是这三步的串联封装,这是理解下面所有语言示例的共同前提。
三、Supported 绑定详解
3.1 JavaScript / TypeScript(prqlcnpm 包)
JavaScript 绑定源码位于 prqlc/bindings/js,通过 WebAssembly 在 Node.js、浏览器和打包器环境中运行。
安装与基础用法
npm install prqlcNode.js 中的直接调用:
const prqlc = require("prqlc"); const sql = prqlc.compile(`from employees | select first_name`); console.log(sql);多行查询同样支持:
const prqlc = require("prqlc"); const sql = prqlc.compile(` from employees select first_name `); console.log(sql);编译选项:CompileOptions支持指定目标方言、是否格式化输出、是否附加签名注释:
const opts = new prqlc.CompileOptions(); opts.target = "sql.mssql"; opts.format = false; opts.signature_comment = false; const sql = prqlc.compile(`from employees | take 10`, opts); console.log(sql);浏览器端(ES Module 直接加载 WebAssembly):
<html> <head> <script type="module"> import init, { compile } from "./dist/web/prqlc_js.js"; await init(); const sql = compile("from employees | select first_name"); console.log(sql); </script> </head> <body></body> </html>框架或打包器场景(如 Vite、Webpack):
import { compile } from "prqlc/dist/bundler"; const sql = compile(`from employees | select first_name`); console.log(sql);暴露的完整函数签名(来自 prqlc/bindings/js/README.md):
function compile(prql_query: string, options?: CompileOptions): string; function prql_to_pl(prql_query: string): string; function pl_to_prql(pl_json: string): string; function pl_to_rq(pl_json: string): string; function rq_to_sql(rq_json: string): string;可见 JS 绑定完整镜像了第二节中的 Rust 核心管线。
错误处理:编译失败时抛出错误,其message是一个 JSON 数组字符串,包含结构化错误信息(类型、错误码、原因、建议、源码位置等):
interface ErrorMessage { kind: "Error" | "Warning" | "Lint"; code: string | null; reason: string; hints: string[]; span: [number, number] | null; display: string | null; location: SourceLocation | null; } interface SourceLocation { start: [number, number]; // [行号, 列号],均从 0 开始 end: [number, number]; }捕获方式:
try { const sql = prqlc.compile(`from employees | foo first_name`); } catch (error) { const errorMessages = JSON.parse(error.message).inner; console.log(errorMessages[0].display); console.log(errorMessages[0].location); }本地开发:npm run build会同时产出 Node、bundler、web 三种目标的dist产物;npm test运行测试。若只想快速迭代,可用PROFILE=dev npm run build跳过 WASM 优化以缩短构建时间。实现上,JS 绑定基于wasm-pack生成,并在其上包了一层 npm 构建脚本,以便用单个包同时分发node、bundler、web三个目标。
3.2 Python(prqlcPyPI 包)
Python 绑定对应 crate 名为prqlc-python(见 prqlc/bindings/prqlc-python),发布到 PyPI 的包名同样是prqlc,基于pyo3实现,底层编译逻辑完全复用 Rust 编译器。
安装与基础用法
pip install prqlcimport prqlc prql_query = """ from employees join salaries (==emp_id) group {employees.dept_id, employees.gender} ( aggregate { avg_salary = average salaries.salary } ) """ options = prqlc.CompileOptions( format=True, signature_comment=True, target="sql.postgres" ) sql = prqlc.compile(prql_query) sql_postgres = prqlc.compile(prql_query, options)暴露的 API 全貌(含默认值,来自 prqlc/bindings/prqlc-python/README.md):
def compile(prql_query: str, options: Optional[CompileOptions] = None) -> str: """Compiles a PRQL query into SQL.""" ... def prql_to_pl(prql_query: str) -> str: """Converts a PRQL query to PL AST in JSON format.""" ... def pl_to_prql(pl_json: str) -> str: """Converts PL AST as a JSON string into a formatted PRQL string.""" ... def pl_to_rq(pl_json: str) -> str: """Resolves and lowers PL AST (JSON) into RQ AST (JSON).""" ... def rq_to_sql(rq_json: str, options: Optional[CompileOptions] = None) -> str: """Converts RQ AST (JSON) into a SQL query.""" ... class CompileOptions: def __init__( self, *, format: bool = True, target: str = "sql.any", signature_comment: bool = True, ) -> None: ... # format:是否对生成的 SQL 进行美化排版(默认 True) # target:目标方言,默认 "sql.any",即由查询头部的 target 参数决定方言; # 可用 get_targets() 查看全部可选方言 # signature_comment:是否在 SQL 末尾附加编译器签名注释(默认 True) def get_targets() -> list[str]: """List available target dialects for compilation.""" ...get_targets()与CompileOptions在 prqlc/bindings/prqlc-python/src/lib.rs 中有对应实现:convert_options会将 Python 侧的CompileOptions转换为 Rust 编译器内部的prqlc_lib::Options,再交给prqlc_lib::compile执行。这也印证了"绑定只是薄壳,真正干活的是 Rust 编译器"这一架构事实。
调试模块prqlc.debug:额外提供列级血缘(lineage)分析能力,属于实验性 API,可能不稳定:
from prqlc import debug def prql_lineage(prql_query: str) -> str: """Computes a column-level lineage graph from a PRQL query. 返回 JSON 字符串,详见 `prqlc debug lineage` CLI 命令。""" ... def pl_to_lineage(pl_json: str) -> str: """Computes a column-level lineage graph from PL AST (JSON).""" ...开发流程:项目使用uv管理依赖,uv run pytest运行测试、uv run ty check做类型检查,也可用task test。该包未被 pyprql、dbt-prql 等项目消费,因而保持较活跃的迭代。
3.3 Rust(prqlccrate)
Rust 绑定就是编译器本身。文档指引读者直接查阅prqlccrate 的 API 文档(rust.md),仓库内的核心入口即 prqlc/prqlc/src/lib.rs。在 Rust 项目中通过 Cargo 引入:
[dependencies] prqlc = "…" # 以 crates.io 上发布的最新版本为准然后即可调用prqlc::compile(prql, &options)、prqlc::prql_to_pl(...)、prqlc::pl_to_rq(...)、prqlc::rq_to_sql(...)等函数(compiler_version()位于 lib.rs#L142)。Rust 绑定天然与编译器同步演进,是其他所有绑定验证 API 兼容性的基准。
3.4 R(prqlr)
R 绑定的包名为prqlr(见 r.md),安装在 CRAN 上发布,从文档可知由社区维护者 @eitsupi 在独立的 PRQL/prqlc-r 仓库中维护。
安装:
install.packages("prqlr")prqlr的一大特色是内置了knitr(R Markdown 与 Quarto)集成:你可以在 R Markdown / Quarto 文档中直接嵌入 PRQL 转换结果,让数据分析报告里的 SQL 生成过程可复现、可展示。
四、Unsupported 绑定详解
4.1 Java(prql-java)
Java 绑定通过JNI调用 Rust 库(源码见 prqlc/bindings/java),在org.prql.prql4j.PrqlCompiler上暴露三个 native 方法:
public static native String toSql(String query, String target, boolean format, boolean signature) throws Exception; public static native String toJson(String query) throws Exception; public static native String format(String query) throws Exception;target:方言名,如sql.mysql(完整列表见 Target and version);format:是否对 SQL 进行美化排版;signature:是否在末尾附加-- Generated by PRQL compiler version:...注释。
该绑定仍处于早期阶段,需要本地编译、尚未发布到 Maven。本地安装到本地 Maven 仓库:
./mvnw install -Dgpg.skip=true注:
java/pom.xml将maven-gpg-plugin绑定在verify阶段,而install会执行该阶段,因此需要-Dgpg.skip=true跳过签名。jar 不内置 native 库,只有deployprofile 的cross.sh会填充src/main/resources,所以消费者需要把工作区target/release下的libprql_java放到java.library.path上。
依赖坐标(<version>与 PRQL 发布版本独立维护):
<dependency> <groupId>org.prqllang</groupId> <artifactId>prql-java</artifactId> <version>0.5.2</version> </dependency>使用示例:
import org.prql.prql4j.PrqlCompiler; class Main { public static void main(String[] args) throws Exception { String sql = PrqlCompiler.toSql("from my_table", "sql.mysql", true, true); System.out.println(sql); } }运行时必须把 native 库加入库路径,否则静态初始化会失败并报libprql_java-linux64.so was not found inside JAR:
java -Djava.library.path=/path/to/prql/target/release Main4.2 Elixir(prql)
Elixir 绑定通过Rustler接入 Rust 编译器(见 prqlc/bindings/elixir)。安装(依赖prql ~> 0.1.0):
def deps do [ {:prql, "~> 0.1.0"} ] end基础用法(交互式验证):
iex> PRQL.compile("from customers", signature_comment: false) {:ok, "SELECT\n *\nFROM\n customers\n"} iex> PRQL.compile("from customers\ntake 10", target: :mssql, signature_comment: false) {:ok, "SELECT\n *\nFROM\n customers\nORDER BY\n (\n SELECT\n NULL\n ) OFFSET 0 ROWS\nFETCH FIRST\n 10 ROWS ONLY\n"}从示例可见:PRQL.compile/2返回{:ok, sql}元组,且支持通过target: :mssql指定方言(这里展示了 MSSQL 的OFFSET/FETCH分页写法)。目前使用需要本地编译 Rust crate:mix deps.get→mix compile→mix test。未来计划发布预编译产物,让 Elixir 项目无需 Rust 工具链即可使用。
4.3 C / C++ / Zig(prqlc-c)
prqlc-c将 PRQL 编译为可供 FFI 调用的 C 库(同时生成.a静态库与.so动态库),任何支持 FFI 的语言(例如 Golang)都可以嵌入使用。完整 FFI 接口在 prqlc.h 中有内联文档,C++ 头文件为 prqlc.hpp。
链接方式(以静态库为例,来自 prqlc/bindings/prqlc-c/README.md):
CGO_LDFLAGS="-L/path/to/target/release -lprqlc_c -pthread -ldl -lm" go build(macOS 上还需追加-framework CoreFoundation。)
示例工程:
- examples/minimal-c/main.c:覆盖
compile、自定义Options、错误处理以及分段式prql_to_pl/pl_to_rq入口; - examples/minimal-cpp:使用生成的 C++ 头文件的等价流程;
- examples/minimal-zig:Zig 通过
@cImport引入prqlc.h的示例。
标准的链接参数可参考 examples/minimal-c/Makefile。头文件由cbindgen生成,重新生成执行task build-prqlc-c-header即可。
五、Nascent 绑定详解
5.1 .NET(prql-net)
.NET 绑定以net10.0库的形式提供(见 prqlc/bindings/dotnet),核心是静态类PrqlCompiler,其Compile、PrqlToPl、PlToRq、RqToSql方法均返回携带Output字符串与Messages列表的Result。尚未发布到 NuGet。
安装:需要将libprqlc_c.so(Linux)、libprqlc_c.dylib(macOS)或libprqlc_c.dll(Windows)与PrqlCompiler.dll一起放入项目bin目录,例如{your_project}/bin/Debug/net10.0/。libprqlc_c库在运行时被动态导入。
使用示例:
using Prql.Compiler; var options = new PrqlCompilerOptions { Format = false, SignatureComment = false, }; var result = PrqlCompiler.Compile("from employees", options); Console.WriteLine(result.Output);该绑定当前版本停在 0.1.0,原因是等待prqlc-c更新到最新 API 后再对齐版本号。
5.2 PHP(prql-php)
PHP 绑定通过FFI调用prqlc(见 prqlc/bindings/php),提供Compiler类,包含compile、prqlToPL、plToRQ、rqToSQL四个方法。尚未发布到 Composer。
安装:需启用 PHP FFI 扩展,在php.ini中设置:
ffi.enable = "true"使用示例:
<?php use Prql\Compiler\Compiler; $prql = new Compiler(); $result = $prql->compile("from employees"); echo $result->output;开发环境:可以使用 nix flake 建立包含 PHP、ext-ffi 与 Composer 的环境(ext-ffi已在composer.json中声明):
mkdir -p ~/.config/nix echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf nix shell github:loophp/nix-shell#env-php81 --impure构建与测试:task build-php会依次执行 cargo 构建libprqlc_c、将libprqlc_c.*与prqlc.h复制进lib;随后task test-php运行测试。代码风格用 PSR12 检查:./vendor/bin/phpcs --standard=PSR12 src tests。
六、命名规范:向prqlc-$lang收敛
按 Bindings 索引文档 的说明,PRQL 团队正逐步统一各绑定的命名约定:
- Rust crate 统一命名为
prqlc-$lang(如prqlc-python、prqlc-c); - 各语言包仓库中的发布名在可能的情况下统一为
prqlc(如 npm 的prqlc、PyPI 的prqlc)。
这也解释了为什么你在安装时会看到"crate 名"与"包名"不完全一致的现象:Rust crate 用带语言后缀的名字区分,而对外发布的包尽量用不带后缀的prqlc,便于用户记忆和统一文档引用。
七、如何选择与上手:快速决策指南
| 你的技术栈 | 推荐绑定 | 安装命令 / 方式 | 成熟度 |
|---|---|---|---|
| Node.js / 浏览器 / 前端 | JavaScript | npm install prqlc | Supported |
| Python / 数据科学 | Python | pip install prqlc | Supported |
| Rust 原生项目 | Rust | 在Cargo.toml引入prqlc | Supported |
| R / R Markdown / Quarto | R | install.packages("prqlr") | Supported |
| Java / JVM | Java | 本地./mvnw install -Dgpg.skip=true | Unsupported |
| Elixir / BEAM | Elixir | mix deps.get后本地编译 | Unsupported |
| Go / Zig / 任意支持 FFI 的语言 | prqlc-c | 链接libprqlc_c | Unsupported |
| .NET / C# | .NET | 拷贝libprqlc_c.*至 bin 目录 | Nascent |
| PHP | PHP | 启用ffi.enable后加载 | Nascent |
核心建议:
- 追求稳定:优先选择 Supported 级绑定,因为它们有维护者、测试覆盖和 API 变更门禁;
- 需要中间 AST:无论哪种语言,都优先使用分段式
prql_to_pl/pl_to_rq/rq_to_sql接口,方便检查或改写中间表示; - 指定方言:编译前用
get_targets()(Python)或查阅 target.md 确认可用方言名,并通过CompileOptions/PrqlCompilerOptions的target参数传入; - 错误排查:编译报错时优先读取结构化错误字段(
kind、code、reason、hints、location),其中的display字段是带标注的代码片段,定位问题最快。
所有绑定的底层能力都来自同一个 Rust 编译器(prqlc/prqlc/src/lib.rs),因此无论你使用哪种语言,PRQL 查询的语法与编译行为都保持一致——学会一种绑定,其他绑定即可举一反三。
【免费下载链接】prqlPRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement项目地址: https://gitcode.com/gh_mirrors/pr/prql
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考