news 2026/5/26 6:33:24

海外开发者实践分享:用 MoonBit 开发 SQLC 插件(其一)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
海外开发者实践分享:用 MoonBit 开发 SQLC 插件(其一)

近日,日本开发者4245ryomt在 Zenn 上发布了一系列围绕MoonBit 与 WebAssembly 插件实践的技术文章,分享了他使用 MoonBit 编写sqlc Wasm 插件的完整尝试过程。

文章通过可运行代码,介绍了插件请求处理、文件生成以及 Wasm 执行等关键环节,展示了 MoonBit 在工具链与 Wasm 场景下的实际开发体验,适合作为相关方向的实践参考。

📄 原文链接:https://zenn.dev/4245ryomt/articles/9680434dc60c0c

↓以下为系列第一篇的原文翻译

本文内容

本文介绍了使用 MoonBit 来制作 sqlc 插件的过程。

本文并不会完成一个能够在 MoonBit 中“很好地执行SQL”的库。

在这个过程中,会用到 在 MoonBit 中使用 protoc,以及 执行由 MoonBit 构建的 wasm。

写着写着发现内容比预期要长,因此拆分成多篇文章。

第 1 篇:将 sqlc 插件的输入用 MoonBit 进行解析。

第 2 篇:将 MoonBit 输出的wasm**作为 sqlc 的插件来使用。

本文中使用的moon命令版本如下:

$ moon version>moon0.1.20251202(1a598002025-12-02)

首先,使用moon new命令创建一个项目。

$ moon new try_moonbit_sqlc_plugin_dev $cdtry_moonbit_sqlc_plugin_dev

什么是 sqlc 插件

sqlc 是一个以SQL作为输入,并生成能够“很好地”执行这些 SQL 的 源代码 的工具。1

这里所说的“很好地”,指的是:

在静态类型语言中,执行 SQL 所需的参数,以及执行后得到的结果,都被指定类型。2

sqlc 的插件本身,就是实现这种“很好地输出”的逻辑。

插件的输入和输出由 protobuf 定义,可以通过标准输入和标准输出,与任意编程语言编写的程序进行通信。

插件有两种执行方式:

一种是作为普通命令,通过标准输入/输出运行的进程类型;

另一种是以 wasm 的形式执行。

MoonBit 的一大优点就是可以输出wasm,因此这次就尝试用 MoonBit 来实现。

用于定义插件输入输出的 protobuf 文件位于 sqlc 仓库中(Lines 1 to 132 in main)。3

将其作为子模块添加进来会比较方便。

$ git submodule add git@github.com:sqlc-dev/sqlc.git sqlc

MoonBit 与 protoc

这里就不展开介绍 Protocol Buffers4是什么了。

从 proto 文件中定义的 schema 出发,用于在各种语言中处理 protobuf 格式消息的工具已经有很多了。

令人惊喜的是,MoonBit 已经存在用于处理 protobuf 消息的工具5

不过,这次要使用的 proto 文件6——codegen.proto,会触发protoc-gen-mbt中的一个缺陷。

只要修改 proto 文件本身即可规避这个问题,所以这里直接进行修改。

$ mkdir proto $ cp -r sqlc/protos/plugin/codegen.proto proto/codegen.proto

params字段名修改为与json_name一致的parameters

message Query{string text=1[json_name="text"];string name=2[json_name="name"];string cmd=3[json_name="cmd"];repeated Column columns=4[json_name="columns"];repeated Parameter params=5[json_name="parameters"];repeated string comments=6[json_name="comments"];string filename=7[json_name="filename"];Identifier insert_into_table=8[json_name="insert_into_table"];}

protoc-gen-mbt是作为protoc命令的插件实现的。

因此只要有protoc命令即可,不过我个人平时更习惯使用buf,所以这里选择使用buf7


从 buf 调用 protoc-gen-mbt

首先,从源码构建protoc-gen-mbt

$gitclone git@github.com:moonbitlang/protoc-gen-mbt.git tmp $cdtmp $ moon build -C cli $cpcli/target/native/release/build/protoc-gen-mbt.exe../protoc-gen-mbt.exe $cd..$rm-rf tmp

接下来,在两个 buf 的配置文件中指定 proto 文件的位置,以及刚刚构建好的protoc-gen-mbt可执行文件。

buf.yaml

version:v2modules:-path:proto

buf.gen.yaml

version:v2inputs:-directory:protoplugins:-local:["./protoc-gen-mbt.exe"]out:.opt:# https://github.com/moonbitlang/protoc-gen-mbt?tab=readme-ov-file#arguments-project_name=sqlc_plugin-json=false-async=false-username=yourname

使用buf generate命令,根据 proto 文件生成 MoonBit 的源代码。

$ buf generate

生成的代码会作为一个 MoonBit 项目输出。

$ tree sqlc_plugin>sqlc_plugin>├── moon.mod.json>└── src>└── plugin>├── moon.pkg.json>└── top.mbt

看看 sqlc 插件的输入内容

在制作 sqlc 插件之前,先来看一下它的输入到底是什么样的。

因此,这里先尝试将标准输入原样输出到标准错误输出

首先,创建一个 shell 可执行文件。

sqlc 的插件在异常退出时,会把标准错误输出的内容记录到日志中。

相反,如果是正常退出,标准错误输出的内容是不会出现在日志里的,这一点需要注意。

dump_stdin_to_stderr.sh

#!/bin/shcat->&2exit1
$chmod+x dump_stdin_to_stderr.sh

为了使用 sqlc 进行代码生成,创建一些示例 SQL 文件。

$mkdirsqlite $touchsqlite/schema.sql $touchsqlite/query.sql

sqlite/schema.sql

CREATE TABLE authors ( id integer PRIMARY KEY AUTOINCREMENT,name text NOT NULL,bio text );

sqlite/query.sql

/* name:get_author:one*/SELECT * FROM authors WHERE id =?LIMIT 1;/* name:list_authors:many*/SELECT * FROM authors ORDER BY name;/* name:create_author:execresult*/INSERT INTO authors ( name,bio ) VALUES (?,?);/* name:delete_author:exec*/DELETE FROM authors WHERE id =?;

创建 sqlc 的配置文件,指定 SQL 文件和插件(shell 可执行文件)。

sqlc.yaml

version:'2'plugins:-name:dump_stdin_to_stderrprocess:cmd:./dump_stdin_to_stderr.shsql:-name:sqliteschema:sqlite/schema.sqlqueries:sqlite/query.sqlengine:sqlitedatabase:uri:file:authors?mode=memory&cache=sharedcodegen:-out:generatedplugin:dump_stdin_to_stderr

执行sqlc generate后,dump_stdin_to_stderr.sh输出的内容会原样显示出来。

$ sqlc generate main ✭ ✱># package dump_stdin_to_stderr>error generating code: process: error runningcommand>p>2sqlitesqlite/schema.sql"sqlite/query.sqlb> > generateddump_stdin_to_stderr* > ump_stdin_to_stderr.sh�main"�main�>authors'>id0���������R authorsb integer&>name0���������R authorsbtext#>bio0���������R authorsbtext�

虽然直接看并不能理解内容,但可以确认:

确实有 protobuf 格式的二进制数据输入了插件。


在 MoonBit 中处理 sqlc 插件的输入

终于到了这里,可以开始编写 MoonBit 代码了。

首先,将必要的模块添加到项目中。

$ moonaddmoonbitlang/async $ moonaddmoonbitlang/protobuf

通过 buf 生成的、定义了 sqlc 插件输入输出的模块,需要直接编辑moon.mod.json来进行引用8

"deps":{"ryota0624/sqlc_plugin":{"version":"0.1.0","path":"./sqlc_plugin"},}

作为运行时入口点的包,其moon.pkg.json如下:

cmd/main/moon.pkg.json

{"is-main":true,"import":[{"path":"yourname/try_moonbit_sqlc_plugin_dev","alias":"lib"},"moonbitlang/async/stdio","moonbitlang/async","moonbitlang/async/io","yourname/sqlc_plugin/plugin","moonbitlang/protobuf"]}

由于GenerateRequest消息中包含了查询名称,因此将这些名称输出到标准错误。

最后,通过调用panic让进程异常退出。

cmd/main/main.mbt

fnmain{@async.run_async_main(main_async)panic()}asyncfnmain_async()->Unit{letinput=@stdio.stdin.read_all()letrequest=@lib.parse_generate_request(input.binary())forqueryinrequest.queries{@stdio.stderr.write(query.name+"\n")}}fnparse_generate_request(data:Bytes)->@plugin.GenerateRequestraise{@protobuf.BytesReader::from_bytes(data)|>@protobuf.Read::read}

使用moon build并指定native作为目标进行构建后,会在

target/native/release/build/cmd/main/main.exe生成可执行文件。

$ moon build --target native

sqlc.yaml中指定该可执行文件。

version:'2'plugins:-name:moonbitprocess:cmd:target/native/release/build/cmd/main/main.exesql:-name:sqliteschema:sqlite/schema.sqlqueries:sqlite/query.sqlengine:sqlitedatabase:uri:file:authors?mode=memory&cache=sharedcodegen:-out:generatedplugin:moonbit

执行sqlc generate后,就会输出查询名称。

& sqlc generate># package moonbit>error generating code:process:error running command get_author>list_authors>create_author>delete_author

  1. https://sqlc.dev/ ↩︎

  2. https://docs.sqlc.dev/en/latest/guides/plugins.html ↩︎

  3. https://github.com/sqlc-dev/sqlc/blob/main/protos/plugin/codegen.proto ↩︎

  4. https://protobuf.dev/ ↩︎

  5. https://github.com/moonbitlang/protoc-gen-mbt ↩︎

  6. https://github.com/moonbitlang/protoc-gen-mbt ↩︎

  7. https://buf.build/product/cli ↩︎

  8. https://github.com/ryota0624/try_moonbit_sqlc_plugin/blob/main/moon.mod.json#L4-L8 ↩︎

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/26 5:51:04

2026年java找工作难吗?java就业环境怎么样?

2026年找工作会“难”,但不是对所有人。 它会呈现出非常明显的 “两极分化” 态势,对初级/基础不牢的求职者: 会非常困难,内卷严重,要求水涨船高。对中高级/有核心竞争力(架构、高并发、云原生等&#xff0…

作者头像 李华
网站建设 2026/5/26 5:55:58

告别生鲜损耗困局:从经验猜货到数据驱动的盈利升级

社区生鲜的盈利枷锁:凭经验进货的损耗困局生鲜损耗是社区生鲜门店盈利的核心障碍,绝大多数管理者都困在“凭经验猜进货” 的被动处境中。就拿社区生鲜店主王哥来说,他虽靠着 “当日鲜采” 的口碑攒下大批忠实熟客,却始终逃不过高损…

作者头像 李华
网站建设 2026/5/25 1:12:43

定制报告-个性化定制-按需专项研究报告-智信中科研究网

定制报告-个性化定制-按需专项研究报告-智信中科研究网市场专项研究报告智信中科研究网个性化定制报告全力解决您的各类需求,为了满足客户在不同发展阶段的不同需求,智信中科研究网可以依据客户的个性化需求,针对性帮助客户完成符合需求的市场…

作者头像 李华
网站建设 2026/5/23 17:40:46

Linux 内存管理:TLB ASID

文章目录1. 前言2. TLB ASID 的硬件支持2.1 概念2.2 TLB 查找3. Linux 下 TLB ASID 管理4. 参考资料1. 前言 限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。 2. TLB ASID 的硬件支持 2.1 概念 什么是 TLB&…

作者头像 李华