排序
排序在查询回调里用 q.orderBy(...) 声明,可传多列、可对表达式排序。
单列与升降序
// ① 模型准备(完整可运行版见工作区)
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.edition, c.price])
const rows = await sqlClient.createQuery(Book, (q, book) => {
q.orderBy(book.price.desc()) // 降序;asc() 是默认,可省
return q.select(book.fetch(BookView))
}).fetchList()
console.log(rows)
多列与混合方向
// ② 多列:先 name 升序(默认),同名的按 edition 降序
const rows2 = await sqlClient.createQuery(Book, (q, book) => {
q.orderBy(book.name, book.edition.desc())
return q.select(book.fetch(BookView))
}).fetchList()
console.log(rows2)
顺序即优先级:前面的列为主键级排序。orderBy 可多次调用(追加)。
表达式排序与子路径
- embedded 子路径排序直接点路径:
q.orderBy(author.name.lastName); - 关联键(引用外键)排序:
q.orderBy(book.storeId); - 表达式/聚合排序:
q.orderBy(dsl.count().desc())(配合聚合与分组,见「聚合与分组」页)。
排序稳定性(重要)
fetchPage/fetchRange 按行切片取数——切片稳定依赖排序唯一性。只看一列排时,值相同的行在页与页之间顺序无保证。要分页/取 TopN,请补一个唯一键做决胜列:
q.orderBy(book.price.desc(), book.id.asc()) // 价格 + id 决胜,页间不漂移
下一步
筛选、排序都齐了。下一节是查询组的高地:取形进阶——扁平化、折叠、递归、输出映射与多态分支。