建议: TypeScript 查询构建器
作者: NickCrews创建于 2026年2月27日更新于 2026年6月5日
我希望在 TypeScript 中构建一个具有卓越、对模式感知的类型安全性的查询构建器。TLDR 类似于这样:
const penguins = prql.table('penguins', {
"species": "string",
"year": "int32",
"bill_length_mm": "float64",
})
const by_year_species = penguins
.group(
r => [r.col("species"), r.col("year")],
g => g
.filter(r => r.col("bill_length_mm").is_not_null())
.agg(
g => ({
count: prql.count(),
mean_length: g.col("bill_length_mm").mean(),
})
)
)
.sort(r => r.col("mean_length"))
.take(10)
const recent_longest_per_year = penguins
.group(
r => r.col("year"),
g => g.sort(r => r.col("bill_length_mm").desc()).take(1)
)
.filter(r => r.col("bill_length_mm").gt(50))
.derive(r => {
bill_length_cm = r.col("bill_length_mm").div(10), // 由于 TypeScript 没有运算符重载,所以需要使用 .div() 来实现
version = prql.sql<"string">("version()"),
})我来自于维护 https://GitHub.com/ibis-project/ibis 的经验,它与 prql 类似,因为它大部分是管道化的,但它确实受到 Python 没有必要跟踪关系模式的复杂类型系统的根限制。它也处于 Python 中,我希望能够在 Web 上使用它。我还在一些 Web 项目中使用了 drizzle ORM 和 zod,我喜欢它们提供的类型安全性,它们展示了如何利用高级 TypeScript 功能来获得出色的 DX。我开始编写上面的原型实现,但我使用了 duckb 的 json_deserialize_sql() 函数将我的 IR 编译为 SQL。但这限制了我只能使用 duckdb,并且要求使用非常 SQL 类似的格式,而我的库则使用非常管道化的格式,因此需要进行大量复杂的转换。然后我想到了 PRQL,它基本上与我在用户面向的 API 中寻找的语义完全一致,并且它还解决了编译问题!因此,我希望转向使用 PRQL 作为编译器,并且在这样做时将语义与 PRQL 保持一一对应(我认为这些语义非常棒!)。
我需要解决的一些问题:
- 是否存在其他先前的艺术作品,我应该考虑?
- 如果我尝试实际实现具有上述语义的查询构建器,你认为我的最大挑战是什么?
- 上面的示例依赖于关系中的所有标量/列的明确类型系统。我阅读了 https://prql-lang.org/book/reference/spec/type-system.html,这是一个很好的开始,但看起来并没有在此做出任何决定。我可以使用什么来作为…
内容来源: PRQL/prql