Effect Model.BooleanSqlite:为 SQLite 布尔列提供 0|1 与 boolean 双边界编码的模型字段
【免费下载链接】effectBuild production-ready applications in TypeScript项目地址: https://gitcode.com/GitHub_Trending/ef/effect
本文围绕 Effect 仓库中的变更记录 bright-dogs-fail.md 展开:该 changeset 声明为effect包新增了一个 patch 级 API——Model.BooleanSqlite,一个数据库变体使用0 | 1编码、JSON 变体使用原生boolean编码的模型字段模式。读完本文,你将理解它在 Effect 4.0 的Model变体模型体系中的定位、底层BooleanFromBit编解码的实现细节,以及如何在你自己的模型中正确使用它并通过测试验证。
变更记录本身说了什么
该 changeset 文件位于 .changeset/pre/bright-dogs-fail.md,正文只有一句话:
Add
Model.BooleanSqlite, a model field schema that uses0 | 1encoding for database variants and plainbooleanencoding for JSON variants.
即:新增Model.BooleanSqlite——一个模型字段模式(model field schema),其中:
- 数据库变体(
select/insert/update)使用0 | 1的位编码; - JSON 变体(
json/jsonCreate/jsonUpdate)使用普通boolean编码。
这一变更对应 packages/effect/CHANGELOG.md 中记录的条目(PR #1622),并属于 Effect v4 中Model模块(@since 4.0.0)的一部分。迁移文档 migration/v3-to-v4.md 还给出了相关的版本对照说明:v3 时代的Model.BooleanFromNumber对应 v4 的核心 schemaBooleanFromBit,而Model.BooleanSqlite则是「开箱即用的模型字段」形态。
为什么需要它:变体模型的基本问题
SQLite 没有原生布尔类型,布尔值通常以整数列0 | 1存储;而面向 HTTP API 的 JSON 表示则应当是true | false。在 Effect 4 的模型体系中,一个字段在不同操作边界(读取数据库、写入数据库、对外输出 JSON)可能需要不同的编码形态。
Model模块正是为此设计的。从 packages/effect/src/unstable/schema/Model.ts 可以看到,模型模式基于VariantSchema工厂生成,固定提供六个变体:
const { Class, Field, FieldExcept, FieldOnly, Struct, Union, extract, fieldEvolve } = VariantSchema.make({ variants: ["select", "insert", "update", "json", "jsonCreate", "jsonUpdate"], defaultVariant: "select" })每个字段通过Field({ ... })按变体名声明各自的 schema;未声明的变体中该字段被整体省略。这样Group.insert就只包含需要用户提供的字段,Group.json就只暴露应当对外可见的字段,且每个变体都是独立可校验、可编解码的 schema。
BooleanSqlite 的源码实现
BooleanSqlite定义在 packages/effect/src/unstable/schema/Model.ts,其类型与构造实现为:
export interface BooleanSqlite extends VariantSchema.Field<{ readonly select: Schema.BooleanFromBit readonly insert: Schema.BooleanFromBit readonly update: Schema.BooleanFromBit readonly json: Schema.Boolean readonly jsonCreate: Schema.Boolean readonly jsonUpdate: Schema.Boolean }> {} export const BooleanSqlite: BooleanSqlite = Field({ select: Schema.BooleanFromBit, insert: Schema.BooleanFromBit, update: Schema.BooleanFromBit, json: Schema.Boolean, jsonCreate: Schema.Boolean, jsonUpdate: Schema.Boolean })可以清晰地看出它对六个变体的完整覆盖:
| 变体 | schema | 编码形态 |
|---|---|---|
select | Schema.BooleanFromBit | 0 \| 1 |
insert | Schema.BooleanFromBit | 0 \| 1 |
update | Schema.BooleanFromBit | 0 \| 1 |
json | Schema.Boolean | true \| false |
jsonCreate | Schema.Boolean | true \| false |
jsonUpdate | Schema.Boolean | true \| false |
也就是说:解码数据库行时接受0 | 1并映射为boolean,编码回数据库时把boolean映射回0 | 1;而在 JSON API 边界上完全使用原生布尔,不做任何位转换。
底层编解码:BooleanFromBit
数据库侧的Schema.BooleanFromBit定义在 packages/effect/src/Schema.ts:
export const BooleanFromBit: BooleanFromBit = Literals([0, 1]).pipe( decodeTo( Boolean, SchemaTransformation.transform({ decode: (bit) => bit === 1, encode: (bool) => bool ? 1 : 0 }) ) )其文档注释明确了语义边界:解码只接受字面量0或1,1映射为true、0映射为false;编码时true映射为1、false映射为0。注意这是严格校验——传入2、"1"等值会触发解码失败,而不是宽松地把「任意真值」当作布尔。这与 SQLite 中「整数列存布尔」的常见约定一致:列里应当只出现0和1。
实际使用:在模型中声明与验证
Model.BooleanSqlite与Model.Struct/Model.Class组合使用。官方测试 packages/effect/test/unstable/schema/VariantSchema.test.ts 提供了可直接复制的完整示例,验证了数据库与 JSON 两侧的编解码行为:
import { Schema } from "effect" import { Model } from "effect/unstable/schema" const User = Model.Struct({ active: Model.BooleanSqlite }) const select = Model.extract(User, "select") // 数据库变体 const json = Model.extract(User, "json") // JSON 变体 Schema.encodeSync(select)({ active: true }) // => { active: 1 } Schema.decodeSync(select)({ active: 0 }) // => { active: false } Schema.encodeSync(json)({ active: true }) // => { active: true } Schema.decodeSync(json)({ active: false }) // => { active: false }这四行断言恰好对应 changeset 描述的两种编码:select 变体编出1、解入0得到false;json 变体则原样保持布尔。
如果你使用Model.Class定义领域模型,字段声明方式完全一致,例如:
import { Model } from "effect/unstable/schema" class Post extends Model.Class<Post>("Post")({ title: Schema.String, published: Model.BooleanSqlite, // DB 列为 0 | 1,JSON 输出为 boolean createdAt: Model.DateTimeInsertFromDate }) {}此时Post(即select变体)用于读取数据库行,Post.insert/Post.update用于写库载荷,Post.json/Post.jsonCreate/Post.jsonUpdate用于 API 输入输出;各变体中published的 TS 类型都是boolean,只有落到数据库边界时才表现为0 | 1。
与同类字段模式的对照
Model模块中还有一批同样按「变体 × schema」声明的现成字段,可帮助判断何时选用BooleanSqlite(见 Model.ts):
GeneratedByDb(schema):字段仅出现在select/json(数据库自增列,插入时不可提供);GeneratedByApp(schema):出现在数据库三变体与json,但不出现在 JSON 创建/更新载荷;Sensitive(schema):仅数据库变体可见,所有 JSON 变体中整体省略(如密码);FieldOption(schema):所有变体可选,数据库变体接受null,JSON 变体接受缺失键且解码为Option;BooleanSqlite:所有变体都可见,仅编码形态按边界区分。
如果字段在数据库与 JSON 中的编码形态相同(比如都是字符串),直接写Schema.String即可;BooleanSqlite专治「同一逻辑值、两种编码形态」的场景。
小结
这条 patch 变更记录对应的Model.BooleanSqlite是 Effect v4 变体模型体系中的一个小而完整的构件:它以六个变体为粒度声明「SQLite 侧用0 | 1、JSON 侧用boolean」的编解码契约,底层复用核心Schema.BooleanFromBit的严格字面量转换,并配套了覆盖两侧编解码的测试用例。对于使用 SQLite 并通过 Effect 构建 API 的项目,把它声明为模型字段后,数据库行与对外 JSON 之间的布尔转换即由类型系统接管,无需在每个读写点手写? 1 : 0。
【免费下载链接】effectBuild production-ready applications in TypeScript项目地址: https://gitcode.com/GitHub_Trending/ef/effect
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考