条件表达式
条件写在列表达式上(book.price.gt(40),不是 where({ price: … }) 对象)。写错属性名或方法名,编译期直接报错——这是 ts-grm 类型安全的核心体验。
比较与区间
// ① 模型准备(与快速上手一致;完整可运行版见工作区)
import { model, prop, dto, dsl, ZodDefault } 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])
const rows = await sqlClient.createQuery(Book, (q, book) => {
q.where(book.price.between(50, 80)) // 数值区间
return q.select(book.fetch(BookView))
}).fetchList()
console.log(rows)
完整清单:
| 表达式 | SQL | 说明 |
|---|---|---|
book.id.eq(3) / .ne(3) | = ? / <> ? | 相等 / 不等 |
book.price.gt(50) .gte(50) .lt(80) .lte(80) | > >= < <= | 可链式:gt(50).lt(80) |
book.price.between(30, 80) | between ? and ? | 闭区间 |
book.id.in(1, 2, 3) | in (?, ?, ?) | 也可传数组 in([1,2,3]) |
book.storeId.isNull() / .notNull() | is null / is not null | 空判断 |
book.name.eqIf(search.name) | — | 动态条件:参数为 null/undefined 时自动省略,见下 |
模糊匹配与 LikeMode
like(区分大小写)/ ilike(不区分)的匹配模式由第二个参数指定,默认 CONTAINS:
book.name.ilike("sql") // CONTAINS:LIKE '%sql%'
book.name.ilike("in action", "ENDS_WITH") // ENDS_WITH:LIKE '%in action'
book.name.like("TS", "STARTS_WITH") // 区分大小写前缀
book.name.ilike("exact-name", "EXACT") // 精确(不区分大小写时的精确匹配)
动态条件:xxxIf
参数驱动的搜索场景(查询表单)最常用。xxxIf 系列在参数为 null/undefined 时自动省略该条件:
// ② 动态条件:价格区间可空,传 null 就跳过
const search = { minPrice: 60 as number | null, maxPrice: null as number | null }
const rows2 = await sqlClient.createQuery(Book, (q, book) => {
q.where(book.price.gteIf(search.minPrice)) // 60 → 生效
q.where(book.price.ltIf(search.maxPrice)) // null → 自动省略
return q.select(book.fetch(BookView))
}).fetchList()
console.log(rows2) // 60 ≤ price 的全部书
eqIf / neIf / gtIf / gteIf / ltIf / lteIf 同族。
逻辑组合
- 多个
q.where(...)之间是 AND; - 需要 OR 时用
dsl.or(...)包谓词:
// ③ OR:价格低 或 书名匹配
const rows3 = await sqlClient.createQuery(Book, (q, book) => {
q.where(
dsl.or(
book.price.lt(50),
book.name.ilike("sql"),
)
)
return q.select(book.fetch(BookView))
}).fetchList()
console.log(rows3)
dsl.and(...)与dsl.or(...)还可嵌套组合复杂谓词;dsl.not(...)取反。
多态判别:is(子类)
条件里按类型过滤用 table.is(SubType)——生成的 SQL 是判别列的范围匹配(含子类派生树):
q.where(book.is(PAPER_BOOK)) // TYPE in('PaperBook', ...)(若 PaperBook 还有派生)
配合取形侧的多态分支($instanceOf)正好组成"多态查询"的完整用法(见「取形进阶」)。
下一步
筛选学会了,下一节排序:多列、升降序、表达式排序与排序稳定性。