自定义数据类型
前置:模型的属性声明请先看 「属性与类型」(本页是其「自定义数据类型」专述)。
内置标量(i64/str/num/…)覆盖多数列。当列的真实语义是“更高级的类型”时(二进制、特定编码、图片对象、自定义枚举存储),用 ScalarProvider 定义自定义数据类型。
结构:值类型 + SQL 类型 + 双向转换
import { ScalarProvider, ScalarType, prop, scalars } from '@ts-grm/core'
import { z } from 'zod'
const binaryProvider = ScalarProvider.of({
valueType: z.instanceof(Uint8Array), // 值的 TypeScript 语义(StandardSchemaV1)
sqlType: ScalarType.binary(1024), // 底层 SQL 类型(BINARY(1024))
toValue: (sqlValue) => sqlValue, // 数据库值 → 应用值
toSql: (value) => value, // 应用值 → 数据库值
})
// 挂到模型属性
image = prop.scalar(binaryProvider)
三个要求:
valueType必须不含 null/undefined(可空用.nullable()表达);toValue / toSql负责数据库 ↔ 应用的形状转换;- 结果:属性在 TS 里是
z.instanceof(...)推导出的类型,库里仍按sqlType存取。
json / jsonb 就是它的实例
prop.json(schema) / prop.jsonb(schema) 的实现就是 ScalarProvider:valueType 是传入的 zod(StandardSchemaV1),sqlType 是 JSON/JSONB,toValue/toSql 做序列化。内置提供 scalars.jsonProvider(valueType) / scalars.jsonbProvider(valueType) 可直接用:
// ① 模型(完整可运行版见工作区)
import { model, prop, dto, scalars } from '@ts-grm/core'
import { z } from 'zod'
import { sqlClient } from './infra/sql-client'
const Book = model("Book", "id", class {
id = prop.i64()
name = prop.str(50)
edition = prop.i32()
price = prop.num(10, 2)
// 自定义数据类型:JSONB 存结构化内容(zod 描述形状)
meta = prop.json(scalars.jsonProvider(z.object({
isbn: z.string(),
rating: z.number().min(1).max(5),
})))
})
// ② 查询普通列(meta 列在沙盒种子中不存在,不放进视图即可)
const rows = await sqlClient.createQuery(Book, (q, b) => {
return q.select(b.fetch(dto.view(Book, c => [c.id, c.name])))
}).fetchList()
console.log(rows)
ts-grm 自带的 StandardSchemaV1
prop.enum / prop.enumSet 内部会构造 vendor: 'ts-grm' 的 StandardSchemaV1 实现,把"值必须 ∈ 集合"表达成 schema 校验——框架的 Nullity 判断等逻辑也会消费它。含义:
- 值类型体系与生态互通(zod、valibot 等 StandardSchema 兼容库都能作
valueType); - 自定义 provider 不必自己实现校验,用现成 zod 即可。
应用场景示例
- 数据库 BINARY → 应用端 Uint8Array / base64 字符串:转换集中在 provider,业务层拿到的就是理想类型;
- 位掩码/枚举编码列:
number存、位运算后解成"特性集合"; - JSONB 与嵌套结构:zod 定义结构,库侧 JSONB,读写自动转换。
边界与提醒
- provider 参与
$allScalars、排序与取形——形状转换以toValue为准; - 列宽/类型必须与
sqlType匹配(createSchema的 DDL 也按它生成); - 性能敏感列(大字段)避免过重转换逻辑。