# 集合函数风格查询

如果你更偏爱类似Scala的集合函数风格的查询方式,也可以使用集合高阶函数风格的api来创建查询:

import easysql.dsl.*

val q = monadicQuery(user).filter(_.id === 1).map(u => u.id -> u.name)

集合函数风格的api并不能使用全部的sql功能,如果你需要使用更多sql功能,或是需要动态创建查询,更推荐使用原生sql风格的api。

# 创建查询

query方法用于创建一个查询:

import easysql.dsl.*

val q = monadicQuery(user)

创建完查询后,可以使用sql方法来生成一个sql语句,以mysql为例:

import easysql.dsl.*

val sql = monadicQuery(user).sql(DB.MYSQL)

生成的语句为:

SELECT `user`.`id`, `user`.`user_name`
FROM `user`

可以看到,query方法会自动展开实体类中定义的字段。

# 条件过滤

使用filter方法来配合前文介绍的表达式生成筛选条件:

import easysql.dsl.*

val sql = monadicQuery(user).filter(_.id === 1).sql(DB.MYSQL)

生成的sql为:

SELECT `user`.`id`, `user`.`user_name`
FROM `user`
WHERE `user`.`id` = 1

# 投影

使用map方法来改变查询结果的类型:

import easysql.dsl.*

val q: MonadicQuery[Tuple1[Int]] = monadicQuery(user).map(_.id)

可以看到,使用map之后,查询返回的类型会被改变,生成的sql如下(以mysql为例):

SELECT `user`.`id`
FROM `user` `user`

高阶函数map合法的返回类型有:Expr表达式,以及由表达式和TableSchema表组成的Tuple元组,比如:

import easysql.dsl.*

val q: monadicQuery(user).map(u => u -> u.name)

# 表连接

使用innerJoinleftJoinrightJoinfullJoin来创建表连接,上述方法都是柯里化的,可以在后面传入连接条件:

import easysql.dsl.*

val q = monadicQuery(a).innerJoin(b)((a, b) => a.x === b.y)

如果三张表join,连接条件中的参数类型就是三元组:

import easysql.dsl.*

val q = monadicQuery(a).innerJoin(b)((a, b) => a.x === b.y).innerJoin(c)((_, b, c) => b.y === c.z)

以此类推。

当然,也可以使用map来改变查询结果类型,不再赘述。

query中可以给表起别名,来处理自连接:

import easysql.dsl.*

val q = monadicQuery(a as "t1").innerJoin(a as "t2")((t1, t2) => t1.x === t2.y)

# 分组

使用groupBy创建分组:

import easysql.dsl.*

val q = monadicQuery(user).groupBy(_.name)

我们需要用map来配合聚合函数表达式简化返回类型:

import easysql.dsl.*

val q = monadicQuery(user).groupBy(_.name).map(u => u.name -> sum(u.id))

# 限制数量

使用droptake限制结果集数量:

import easysql.dsl.*

val q = monadicQuery(user).drop(10).take(10)

# 排序

使用sortBy添加排序:

import easysql.dsl.*

val q = monadicQuery(user).sortBy(_.id.asc).sortBy(_.name.desc)

# 聚合的简写形式

我们想查询一个聚合后的结果,固然可以使用聚合函数类型的表达式:

import easysql.dsl.*

val q = monadicQuery(user).map(u => count())

但这可能不太方便,我们可以这样来简写:

import easysql.dsl.*

val count = monadicQuery(user).size
val sum = monadicQuery(user).sum(_.id)
val max = monadicQuery(user).max(_.id)
val min = monadicQuery(user).min(_.id)
val avg = monadicQuery(user).avg(_.id)

# exists

对于单字段查询,我们可以使用exists方法来生成查询结果是否存在的sql:

import easysql.dsl.*

val q = monadicQuery(user).filter(_.id > 10000).map(_.id).exists

生成的sql为:

SELECT EXISTS (
    SELECT `user`.`id`
    FROM `user`
    WHERE `user`.`id` > 10000
)

# monadic查询

集合函数风格的api实现了mapwithFilterflatMap,因此,在内连接表的情况下,我们也可以使用for表达式来创建查询:

import easysql.dsl.*

val q = for {
    u <- monadicQuery(user) if u.name === "abc"
    p <- monadicQuery(post) if u.id === post.userId
} yield (u, p)