
PRQL Elixir Bindings在 Elixir 中编译 PRQL 查询为 SQL 的完整指南【免费下载链接】prqlPRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement项目地址: https://gitcode.com/gh_mirrors/pr/prqlPRQLPipelined Relational Query Language是一种用于数据转换的现代语言它通过管道式的语法取代传统 SQL 中繁琐的嵌套结构。本仓库为 Elixir 语言提供了基于 Rustler NIF 的官方绑定位于 prqlc/bindings/elixir让你可以在 Elixir 项目中直接调用PRQL.compile/2将 PRQL 源码编译为各数据库方言的 SQL。读完本文你将掌握该绑定的安装方式、PRQL模块的全部公开 API含编译选项与错误处理、底层 Rust NIF 的实现原理以及如何在本地用mix完成依赖安装、编译与测试。一、绑定概览Rust 核心 Elixir 外壳PRQL 编译器的主体由 Rust 实现核心 crate 为prqlcElixir 绑定并没有重写编译器而是通过 Rustler 将 Rust 编写的 NIFNative Implemented Function暴露给 Elixir 调用。从仓库结构可以看到清晰的三层设计Elixir 公共 APIlib/prql.ex 定义了PRQL模块是用户直接调用的入口NIF 声明层lib/prql/native.ex 使用use Rustler, otp_app: :prql声明 NIF 函数及PRQL.Native.CompileOptions结构体Rust 实现层native/prql/src/lib.rs 是实际执行编译的 NIF 实现通过rustler::init!(Elixir.PRQL.Native)注册到 Elixir 模块。此外native/prql/Cargo.toml 中声明了该 NIF crate 依赖仓库内的prqlcpath ../../../../prqlc与rustler 0.38.0并以crate-type [cdylib]编译为动态库供 BEAM 加载。二、安装与项目依赖2.1 通过 Hex 添加依赖README 中给出的标准安装方式是在mix.exs的deps/0中添加def deps do [ {:prql, ~ 0.1.0} ] end当前绑定版本为0.1.0见 mix.exs 中的version: 0.1.0项目要求 Elixir~ 1.15。除prql本身外mix.exs 还声明了两个依赖{:rustler, ~ 0.38.0}, {:ex_doc, ~ 0.21, only: :dev, runtime: false}其中rustler是编译 NIF 的运行时依赖ex_doc仅用于开发环境生成文档。2.2 从仓库源码本地接入由于绑定仍处于早期开发阶段README 明确指出目前在一个 Elixir 项目中使用该绑定需要从本仓库编译 Rust crate而不是直接拉取预编译产物。对应的步骤为mix deps.get # 安装 Mix 依赖 mix compile # 编译项目会同时触发 Rustler 编译 NIF mix test # 运行测试mix compile阶段 Rustler 会自动调用cargo编译native/prql目录下的 NIF crate。README 同时提到后续计划发布预编译产物届时 Elixir 项目将无需本地 Rust 工具链即可运行 PRQL——这属于尚未落地的未来工作当前使用仍需具备 Rust 环境。三、基本用法PRQL 到 SQL 的编译3.1 最简单的编译README 给出的第一个示例展示了默认目标Generic 方言下的编译iex PRQL.compile(from customers, signature_comment: false) {:ok, SELECT\n *\nFROM\n customers\n}PRQL.compile/2返回{:ok, sql}或{:error, reason}元组其中reason是 JSON 字符串。生成的标准 SQL 可以直接交给任意 SQL 驱动执行。3.2 指定目标方言第二个示例展示了指定 MSSQL 方言后take转换被生成 SQL Server 风格的OFFSET ... FETCH FIRST分页写法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}这说明:target选项会直接影响底层 SQL 生成器的方言选择详见下文“编译选项”一节。3.3 完整的公开 API从 lib/prql.ex 的源码看PRQL模块共暴露 8 个函数每个都提供“返回元组”与“出错即抛出异常”两种形态函数说明成功返回失败行为compile/2将 PRQL 字符串一次性编译为 SQL{:ok, sql}{:error, json_string}compile!/2同compile/2失败时抛出PRQL.PRQLErrorsqlraiseprql_to_pl/1将 PRQL 解析为 PLPipelined LanguageAST 的 JSON{:ok, pl_json}{:error, json_string}prql_to_pl!/1同prql_to_pl/1失败时抛出异常pl_jsonraisepl_to_rq/1将 PL AST 的 JSON 转换为 RQRelational QueryAST 的 JSON{:ok, rq_json}{:error, json_string}pl_to_rq!/1同pl_to_rq/1失败时抛出异常rq_jsonraiserq_to_sql/1将 RQ AST 的 JSON 编译为 SQL{:ok, sql}{:error, json_string}rq_to_sql!/1同rq_to_sql/1失败时抛出异常sqlraise后三组函数暴露了 PRQL 编译流水线的中间阶段即PRQL → PL AST → RQ AST → SQL适用于需要检查或加工中间 AST 的场景。其底层实现位于 native/prql/src/lib.rsprql_to_pl实际调用prqlc::prql_to_pl后经prqlc::json::from_pl序列化为 JSONpl_to_rq先json::to_pl反序列化再prqlc::pl_to_rq后json::from_rq序列化rq_to_sql则先json::to_rq再以prqlc::Options::default()调用prqlc::rq_to_sql源码注释指出当前该函数暂未透传编译选项。四、编译选项详解compile/2的第二个参数是一个关键字列表选项类型在 lib/prql.ex 中定义为compile_opts()并在 lib/prql/native.ex 的PRQL.Native.CompileOptions中给出默认值选项类型默认值说明:targetatom:generic生成 SQL 使用的方言见下方列表:formatbooleantrue是否对生成的 SQL 进行格式化多行、缩进美化:signature_commentbooleantrue是否在生成的 SQL 后追加编译器的签名注释:target支持的值源码类型定义与 Rust 端原子均一致包括:generic、:mssql、:mysql、:postgres、:ansi、:bigquery、:clickhouse、:duckdb、:oracle、:redshift、:sqlite、:snowflake。需要特别注意的是方言的优先级规则这里显式传入的:target永远优先于查询头中的target:sql.…参数且不存在“回退到查询头”的取值。这一点在 lib/prql.ex 的文档注释与 native/prql/src/lib.rs 中均有明确说明。在 Rust 端CompileOptions结构体通过impl FromCompileOptions for prqlc::Options转换为编译器选项format、target、signature_comment一一对应同时强制设置display: prqlc::DisplayOptions::Plain。target_from_atom/1将 Elixir 原子逐一映射到prqlc::sql::Dialect枚举Ansi、BigQuery、ClickHouse、DuckDb、MsSql、MySql、Oracle、Postgres、Redshift、SQLite、Snowflake、Generic任何未识别的原子都会安全回退到Generic方言不会导致崩溃。五、错误处理与返回约定5.1 返回元组与 JSON 错误所有非!版本函数都返回{:ok, binary()} | {:error, binary()}。错误分支中的二进制内容是编译器产出的JSON 字符串需要自行用Jason等 JSON 库解析。Rust 端的to_result_tuple/1见 native/prql/src/lib.rs负责这一转换编译成功时包装为{:ok, sql}失败时调用prqlc::ErrorMessages的to_json()生成错误 JSON。5.2 PRQL.PRQLError 异常compile!/2、prql_to_pl!/1、pl_to_rq!/1、rq_to_sql!/1在失败时会抛出 lib/prql/errors.ex 中定义的PRQL.PRQLError异常。该异常的:error字段保存编译器返回的 JSON 错误信息:message固定为Error compiling PRQL querydefexception [:message, :error] def exception(err) do %__MODULE__{message: Error compiling PRQL query, error: err} end5.3 错误 JSON 的结构test/prql_test.exs 中的“返回无效查询错误”测试给出了错误 JSON 的完整结构以编译invalid为例{ inner: [ { kind: Error, code: null, reason: Unknown name invalid, hints: [], span: 1:0-7, display: Error: \n ╭─[ :1:1 ]\n │\n 1 │ invalid\n │ ───┬─── \n │ ╰───── Unknown name invalid\n───╯\n, location: { start: [0, 0], end: [0, 7] } } ] }可以看到每条错误包含kind错误级别、reason可读的错误原因、hints修复提示、span源码位置区间以及带彩色框线的display终端友好格式开发者可以据此实现自定义的错误展示。六、测试与本地开发绑定自带完整的 ExUnit 测试入口为 test/test_helper.exs仅一行ExUnit.start()。测试用例集中在 test/prql_test.exsDoctestdoctest PRQL会直接校验 lib/prql.ex 文档注释中的 IEx 示例保证 README 与文档中的示例始终与实现一致正常编译测试断言PRQL.compile(from customers, signature_comment: false)输出多行格式化 SQL错误路径测试断言编译非法查询时返回的 JSON 错误结构符合预期。本地开发流程即 README 中的三条命令mix deps.get mix compile mix test编译时请确保已安装 Rust 工具链NIF crate 依赖prqlc的源码编译且当前阶段尚未提供预编译产物。七、小结PRQL 的 Elixir 绑定通过 Rustler NIF 把prqlc编译器的能力无缝接入 BEAM 生态目前提供compile/2等 8 个公开函数覆盖“PRQL → SQL”完整链路与PL AST、RQ AST两个中间阶段的转换支持 12 种 SQL 方言和格式化、签名注释等编译选项。对于需要在 Elixir / Phoenix 应用中直接编写管道式查询并翻译为各数据库 SQL 的场景这是一个开箱即用的轻量方案。需要注意的是当前版本0.1.0仍处于早期阶段使用前需确认本机具备 Rust 工具链。想深入了解实现细节可继续阅读仓库内的以下文件PRQL 语言书籍、绑定总览、Elixir 公共 API 源码、Rust NIF 实现以及测试用例。【免费下载链接】prqlPRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement项目地址: https://gitcode.com/gh_mirrors/pr/prql创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考