当前位置: 首页 > news >正文

海外开发者实践分享:用 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 ↩︎

http://www.jsqmd.com/news/106389/

相关文章:

  • 基于大数据的安阳市空气质量预测分析系统的设计与实现开题报告
  • 几种不同的技师展示、推荐形式,每个客户一上来就能找到喜欢的技师,立刻下单!
  • 非官方接口实现中数据安全与隐私保护的考量
  • Android-packages/modules-由来及子目录介绍
  • 28、Linux 文件共享与备份全攻略
  • 基于大数据的餐饮食材管理系统的设计与实现开题报告
  • 健康管理实训室:解锁康养技能提升新路径
  • 基于SpringBoot的鸟博士微信小程序设计与实现(程序+文档+讲解)
  • 基于大模型LLM的开发与编程教程
  • 基于大数据的哔哩哔哩视频数据分析可视化系统开题报告
  • 基于SpringBoot的企业财务管理信息系统的设计与实现(程序+文档+讲解)
  • springboot+jspm宠物医院药房管理系统的研究与实现_47e81477
  • Android-Audio-为啥不移到packages/module
  • 2025 OA 选型关键看这 4 点:集成、灵活、安全、易用,附高性价比系统清单
  • Flink startNewChain 核心解析
  • MySQL参数配置一次说清楚
  • 41、深入探究Linux文件共享与编程开发
  • 图神经网络与pytorch
  • 读捍卫隐私09匿名指南
  • Flink 翻滚窗口、滑动窗口、会话窗口核心区别
  • FreeBuds Pro5续航短?关闭这些设置试试!
  • C#中的静态成员、常量和只读变量
  • centos7 磁盘I/O性能
  • 软硬协同:揭秘机器狗复杂地形适应背后的边缘智能中枢
  • 架构设计:ElasticSearch+HBase 海量存储架构设计与实现
  • Simulink仿真模型中同步电机的死区补偿与自适应补偿实践
  • 水面上划过的涟漪遇到礁石会拐弯,声波撞上超表面也得乖乖听话。今天咱们来折腾COMSOL里水声超表面的反射特性计算,这玩意儿在声学隐身和定向传声领域正热乎着呢
  • CPT、SFT、DPO分别是什么
  • Flink Join 核心解析:类型、原理、实操
  • 一种“看起来很稳”,却暗藏坑点的恒流 PWM 驱动电路