Skip to content

动态构建查询

sqala提供了静态且类型安全的DSL用于构建查询,但也支持在一定程度上构建动态查询,以下是一些常用用例。

动态排序

sqala对于过滤操作提供了filterIf,但对于排序没有提供类似的操作,但我们可以在sortBy的函数里编写类似这样的代码,以达到动态排序目的:

scala
// 假设是用户传参
val key: String = ???

val q = query:
    from(Post).sortBy: p =>
        key match
            case "likeCount" => p.likeCount.desc
            case "viewCount" => p.viewCount.desc
            case _ => p.id.asc

动态分组

对于groupBy这样类型要求比较严格的方法,我们可以以外置控制流的方式来做到动态查询:

scala
case class Data(dim1: Int, dim2: Int, dim3: Int, measure: Int)

val dim: Int = ???

val q = query:
    val baseQuery = from(Data)

    val grouping = if dim == 1 then
        baseQuery.groupBy(d => d.dim1)
    else if dim == 2 then
        baseQuery.groupBy(d => d.dim2)
    else
        baseQuery.groupBy(d => d.dim3)
        
    grouping.map((g, d) => (g, sum(d.measure)))

按列表生成OR条件

对于某些早期版本的数据库,可能无法在IN中使用索引,因此我们可以使用OR连接条件的方式,我们可以这样构造这样的动态查询:

scala
val list = List(1, 2, 3)

val q = query:
    from(User).filter(u => list.map(i => u.id == i).reduce((x, y) => x || y))

封装共用操作

由于sqala的各种操作实际上都是产生一个对象,因此我们可以很容易地将其封装在方法内,但请注意,这样的封装方法需要(using QueryContext)

scala
def joinTable(using QueryContext) = Post.join(Comment).on((p, c) => p.id == c.postId)

val q1 = query:
    from(joinTable).filter((p, _) => p.id == 1)

val q2 = query:
    from(joinTable).sortBy((p, c) => (p.title, c.title))

提升可读性

在同一个query上下文里,我们可以将子查询等结构提出一个变量来提高代码可读性:

scala
val q = query:
    val avgQuery = from(Post).map(p => avg(e.likeCount))

    from(Post).filter(p => p.likeCount > avgQuery)