后端【免费下载链接】prqlPRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement项目地址https://gitcode.com/gh_mirrors/pr/prql点击查看免费下载本指南围绕 PRQL 仓库中的 Elixir 语言绑定位于 prqlc/bindings/elixir/README.md并被文档站点收录于 web/book/src/project/bindings/elixir.md展开介绍如何在 Elixir 项目中安装、调用PRQL.compile/2将 PRQL 管道式查询编译为 SQL并结合仓库源码剖析其 Rustler NIF 桥接层的实现原理、参数语义与开发测试流程。读完本文你将能够在自己的 Elixir 应用中直接驱动prqlc编译器并理解其编译管线的每一层PRQL → PL AST → RQ → SQL对应的 Elixir API。一、什么是 PRQL 的 Elixir 绑定PRQLPipelined Relational Query Language是一种面向数据转换的现代查询语言目标是成为 SQL 的管道式替代品。PRQL 编译器的核心是 Rust crateprqlc位于本仓库的 prqlc/prqlc 目录。为了让 Elixir 生态也能使用这一编译器仓库维护了一套独立的 Elixir 绑定工程其入口即 prqlc/bindings/elixir/README.md。该绑定基于Rustler实现Rustler 是 Elixir 社区中编写 Rust NIFNative Implemented Function原生函数的标准库它把prqlc的编译能力以原生函数的形式暴露给 Erlang VMElixir 侧则通过一个PRQL模块封装调用。从绑定分级来看Elixir 目前被归类为Unsupported非官方支持层级——功能可用但尚未达到需要维护者、完整测试覆盖、发布到官方包仓库等Supported标准详见 web/book/src/project/bindings/README.md 中的分级说明。二、安装与依赖2.1 在 mix 项目中引入依赖在mix.exs的deps/0中添加依赖def deps do [ {:prql, ~ 0.1.0} ] end随后执行mix deps.get拉取依赖。当前绑定工程的版本为0.1.0对 Elixir 的要求是~ 1.15见 prqlc/bindings/elixir/mix.exs 中project/0的声明。2.2 需要 Rust 工具链需要特别注意的是在写本文时该绑定尚未发布预编译产物。README 明确说明当前在 Elixir 项目中使用该绑定需要从本仓库源码编译 Rust crateprqlc/bindings/elixir/README.md的 Development 一节。也就是说开发/运行环境必须具备 Rust 工具链且mix compile时会触发对 NIF 的本地编译。绑定侧的依赖声明位于 prqlc/bindings/elixir/native/prql/Cargo.tomlprqlc以path ../../../../prqlc指向仓库内的编译器本体版本对应0.13.15并关闭默认特性default-features falserustler 0.38.0NIF 桥接库crate 类型为cdylib即编译为可供 Erlang VM 动态加载的共享库。Elixir 侧的构建依赖同样由 mix.exs 声明{:rustler, ~ 0.38.0}与仅开发期使用的{:ex_doc, ~ 0.21}。三、基本用法把 PRQL 编译为 SQL绑定对外暴露的入口是PRQL.compile/2。以下两个示例直接取自绑定 README也是PRQL模块的 doctest 用例见 prqlc/bindings/elixir/lib/prql.ex 中的doc与 prqlc/bindings/elixir/test/prql_test.exsiex 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}可以观察到两点返回值是{:ok, sql_string}元组成功时第二个元素就是可直接交给 SQL 驱动执行的 SQL 文本方言参数影响输出take 10在默认的:generic方言与:mssql方言下会生成不同的分页语法——MSSQL 使用OFFSET 0 ROWS ... FETCH FIRST 10 ROWS ONLY表达取前 10 行这正体现了 PRQL 面向多种 SQL 方言编译的能力。四、compile/2 的完整参数语义PRQL.compile(prql_query, opts \\ [])接受两个参数待编译的 PRQL 查询字符串以及关键字选项列表。其类型约束为when is_binary(prql_query) and is_list(opts)见 lib/prql.ex并通过struct(CompileOptions, opts)将选项结构化为 NIF 侧期望的 struct。4.1 target目标 SQL 方言target决定生成的 SQL 面向哪种数据库方言支持以下 12 个原子值原子值对应 prqlc 方言典型场景:genericGeneric默认通用 SQL:mssqlMsSqlMicrosoft SQL Server:mysqlMySqlMySQL:postgresPostgresPostgreSQL:ansiAnsiANSI 标准 SQL:bigqueryBigQueryGoogle BigQuery:clickhouseClickHouseClickHouse:duckdbDuckDbDuckDB:oracleOracleOracle:redshiftRedshiftAmazon Redshift:sqliteSQLiteSQLite:snowflakeSnowflakeSnowflake该参数默认值为:generic。有两个值得注意的语义未知原子回退到:genericRust 侧的target_from_atom见 native/prql/src/lib.rs会逐一分发各方言原子落入else分支时统一使用Generic方言始终优先于查询头doc中明确说明这里的方言总是胜过查询头中的target:sql.…参数且没有可以回退到查询头的值——即无法通过查询内声明覆盖compile/2传入的target。4.2 formatSQL 格式化开关format为布尔值控制是否将生成的 SQL 交给格式化器进行多行拆分与缩进美化默认值为true。README 与 doctest 中大量使用signature_comment: false正是为了让输出更简洁、便于断言。4.3 signature_comment签名注释开关signature_comment为布尔值控制是否在生成的 SQL 后附加编译器签名注释默认值为true。以上三个选项的默认值可以在 NIF 侧的 struct 定义中确认native/prql/src/lib.rsdefstruct target: :generic, format: true, signature_comment: true而在 Elixir 侧对应的类型声明位于 lib/prql/native.ex 的PRQL.Native.CompileOptions其t/0类型包含target: target(), format: boolean(), signature_comment: boolean()三个字段。Rust 侧将CompileOptions转换为prqlc::Options的实现impl FromCompileOptions for prqlc::Options进一步印证了选项的传递链路format、target、signature_comment直接映射到prqlc::Options对应字段同时固定设置display: prqlc::DisplayOptions::Plain即不做额外的展示层格式化。五、错误处理与 compile!/25.1 错误返回结构当查询无法编译时compile/2返回{:error, reason}其中reason是一个JSON 字符串。测试用例 prql_test.exs 给出了完整的错误 JSON 结构示例——对于查询invalid返回的错误 JSON 包含inner数组每个元素含kind、code、reason、hints、span、display带源码标注的可读错误信息与location起始/结束行列坐标等字段。这得益于 Rust 侧to_result_tuple的实现prqlc::ErrorMessages会被序列化为 JSONe.to_json()作为{:error, json}元组的第二个元素返回。在应用侧你可以用任意 JSON 解码库如Jason解析该错误字符串从中提取span如1:0-7与display字段做进一步展示或定位。5.2 断言式 APIcompile!/2如果希望出错时直接抛出异常而非返回元组可以使用compile!/2spec compile!(binary(), [compile_opts()]) :: binary() def compile!(prql_query, opts \\ []) do case compile(prql_query, opts) do {:ok, result} - result {:error, reason} - raise PRQL.PRQLError, reason end endcompile!/2成功时直接返回 SQL 字符串失败时抛出PRQL.PRQLError异常。异常模块定义在 lib/prql/errors.ex它基于defexception [:message, :error]exception/1回调将message固定为Error compiling PRQL query原始错误 JSON 存放在:error字段中。六、编译器管线的逐层 API除了端到端的compile/2绑定还暴露了 PRQL 编译器内部三条管线的逐步调用函数对应prqlc库的核心编译流程Elixir 函数阶段输入输出prql_to_pl/1PRQL → PL ASTJSONPRQL 查询字符串{:ok, pl_json}或{:error, json}pl_to_rq/1PL ASTJSON → RQJSONPL 的 JSON 表示{:ok, rq_json}或{:error, json}rq_to_sql/1RQJSON → SQLRQ 的 JSON 表示{:ok, sql}或{:error, json}每个函数都有对应的!版本prql_to_pl!/1、pl_to_rq!/1、rq_to_sql!/1语义与compile!/2一致成功返回字符串失败抛出PRQL.PRQLError。Rust 侧实现native/prql/src/lib.rs揭示了这些函数与prqlc库的对应关系prql_to_plprqlc::prql_to_pl解析出 PL AST 后再经prqlc::json::from_pl序列化为 JSONpl_to_rq先prqlc::json::to_pl反序列化 PL JSON经prqlc::pl_to_rq生成 RQ再由prqlc::json::from_rq输出 JSONrq_to_sql先prqlc::json::to_rq反序列化 RQ JSON再调用prqlc::rq_to_sql生成 SQL——代码注释也指出此处目前只使用默认 Options。这套分层 API 对需要自定义编译管线例如在 PL/RQ 层做分析或转换的 Elixir 开发者非常有用可以嵌入自己的中间处理步骤。七、架构原理Elixir 如何调用 Rust 编译器绑定采用标准的 Rustler NIF 架构整体数据流如下Elixir 调用层lib/prql.ex 的PRQL模块将用户参数结构化为PRQL.Native.CompileOptions调用PRQL.Native.compile/2等 NIF 函数NIF 占位层lib/prql/native.ex 使用use Rustler, otp_app: :prql声明 NIF 宿主模块。未加载 NIF 时各函数返回:erlang.nif_error(:nif_not_loaded)保证模块在无原生库环境下仍可加载Rust 实现层native/prql/src/lib.rs 通过#[rustler::nif]标注四个导出函数并以rustler::init!(Elixir.PRQL.Native)注册到名为Elixir.PRQL.Native的模块返回值编码Rust 侧把ResultString, prqlc::ErrorMessages统一转换为Response一个NifTuple包含:ok/:error原子与结果字符串映射为 Elixir 的{:ok, binary()} | {:error, binary()}元组。值得注意的实现细节Rust 侧CompileOptions通过#[derive(NifStruct)]与#[module PRQL.Native.CompileOptions]声明与 Elixir struct 的映射关系因此 Elixir 侧struct(CompileOptions, opts)生成的 struct 可以直接作为 NIF 参数传递。另外该 crate 在wasm目标下被显式排除#![cfg(not(target_family wasm))]表明它面向原生环境运行。八、开发与测试流程README 的 Development 一节给出了本地开发的三个标准步骤mix deps.get # 安装 Elixir 依赖 mix compile # 编译工程含 Rust NIF mix test # 运行测试测试工程包含 test/prql_test.exs 与 test/test_helper.exs。其中测试覆盖了两类核心场景成功路径PRQL.compile(from customers, signature_comment: false)断言其输出与预期 SQL 完全一致错误路径PRQL.compile(invalid, ...)断言返回的{:error, json}经Jason.decode后与预期的错误结构逐字段相等。此外prql_test.exs中的doctest PRQL会直接执行PRQL模块doc中的 doctest 示例确保文档中的用法示例持续可验证。NIF 的构建说明见 native/prql/README.mdNIF 会随项目一起编译并自动加载进PRQL.Native模块。九、当前状态与未来规划绑定 README 明确标注我们正处于 Elixir 绑定的早期开发阶段We are in the early stages of developing Elixir bindings。从 web/book/src/project/bindings/README.md 的分级看Elixir 绑定当前属于Unsupported层级功能可正常工作但尚未满足 Supported 所需的条件有维护者、覆盖核心编译函数及对应测试、发布到语言官方包仓库、在Taskfile.yaml提供开发环境引导脚本等。README 提及的未来工作包括发布预编译产物届时 Elixir 项目将无需本地 Rust 工具链即可直接使用 PRQL 编译能力。在此之前任何使用该绑定的 Elixir 项目都依赖 Rust 工具链与仓库内prqlccrate 的本地编译。十、小结本文围绕 PRQL 的 Elixir 绑定完整覆盖了从依赖安装、PRQL.compile/2基本用法、三大编译选项target/format/signature_comment语义、错误处理与compile!/2、编译器逐层 API到 Rustler NIF 桥接层源码剖析与开发测试流程的全部内容。你可以基于 prqlc/bindings/elixir/lib/prql.ex 的公开 API 直接集成也可以参考 native/prql/src/lib.rs 理解底层调用链从而在 Elixir 项目中获得完整的 PRQL 编译能力。赞分享后端【免费下载链接】prqlPRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement项目地址https://gitcode.com/gh_mirrors/pr/prql点击查看免费下载相关推荐PRQL Elixir Bindings在 Elixir 中编译 PRQL 查询为 SQL 的完整指南PRQL Elixir Bindings在 Elixir 中编译 PRQL 查询为 SQL 的完整指南 PRQLPipelined Relational Q后端使用 prql-php通过 PHP FFI 调用 PRQL 编译器将 PRQL 查询编译为 SQL使用 prql php通过 PHP FFI 调用 PRQL 编译器将 PRQL 查询编译为 SQL PRQLPipelined Relational Que后端PRQL PHP 绑定指南使用 prql-php 通过 FFI 将 PRQL 编译为 SQLPRQL PHP 绑定指南使用 prql php 通过 FFI 将 PRQL 编译为 SQL prql php 是 PRQL 编译器在 PHP 生态中的官方绑后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考