TSts-grm

根查询与取形

所有查询从 sqlClient.createQuery(model, (q, table) => …) 开始。回调里拿到查询构建器 q表对象 table,用链式调用描述查询,最后 select 定形状、收尾方法执行。

// ① 模型与视图(与快速上手章一致,示例数据可直接运行)
import { model, prop, dto } from '@ts-grm/core'
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)
})

const BookView = dto.view(Book, c => [
    c.id,
    c.name,
    c.price,
])

// ② 根查询:where/orderBy 可省略,select 决定形状
const rows = await sqlClient.createQuery(Book, (q, book) => {
    return q.select(book.fetch(BookView))   // 形状 = 视图
}).fetchList()

console.log(rows)

select 的三种形态

形态写法结果
视图取形q.select(book.fetch(View))按视图的精确 DTO,最常用
映射投影q.select({ book, rank })自定义键名/混合多段表达式(rank 可以是原生 SQL、公式等)
聚合投影q.select(dsl.count()) / q.select(book.name, dsl.max(book.edition))聚合结果(配合 groupBy,见「聚合与分组」)

映射投影示例(键名自定义,可混入列表达式):

// ③ 映射投影:book 视图 + 价格列,键名自定
const rows2 = await sqlClient.createQuery(Book, (q, book) => {
    return q.select({
        item: book.fetch(BookView),
        price: book.price,
    })
}).fetchList()

console.log(rows2.map(r => `${r.item.name.padEnd(28)} → ${r.price}`).join('\n'))

收尾方法:按"想要几行"选择

创建查询对象后,用一个收尾方法执行:

方法语义返回
fetchList()多行T[]
fetchRequired()恰好一行:0 行 NoDataError、多行 TooManyDataErrorT
fetchOptional()至多一行:无行返回 null{ nullAsUndefined: true }undefinedT | null
fetchCount()行数number

例:读某本书(不存在时返回 null):

// ④ fetchOptional:至多一行
const maybe = await sqlClient.createQuery(Book, (q, book) => {
    q.where(book.id.eq(99))               // 不存在
    return q.select(book.fetch(BookView))
}).fetchOptional()

console.log('id=99 →', maybe)   // null

没有 .fetchOne()——"必须有且仅有一行"用 fetchRequired();"至多一行"用 fetchOptional()

查询是延迟构建的

createQuery(...) 本身不执行:只有调用收尾方法才真正生成 SQL 并执行(这也是 createQuery 能作为工厂被复用/传给子查询、计算属性等的原因)。

下一步

查询骨架有了,下一节是条件表达式的全部武器:比较、区间、IN、模糊与动态条件