Slick:有没有办法用正则表达式创建 WHERE 子句?

Sto*_*cki 3 regex scala slick

我寻找一个光滑的相当于

select * from users where last_name ~* '[\w]*son';
Run Code Online (Sandbox Code Playgroud)

例如,当数据库中有以下名称时:

first_name | last_name
----------------------
Tore       | Isakson
John       | Smith
Solveig    | Larsson
Marc       | Finnigan
Run Code Online (Sandbox Code Playgroud)

结果是

first_name | last_name
----------------------
Tore       | Isakson
Solveig    | Larsson
Run Code Online (Sandbox Code Playgroud)

我当前的解决方案是使用 SQLActionBuilder 插入它,例如

val pattern = "[\\w]*son"
val action = sql""" SELECT * FROM users WHERE last_name ~* ${pattern}; """.as[User]
Run Code Online (Sandbox Code Playgroud)

但这不是我想要的方式。我更喜欢类似的东西

users.filter(_.last_name matchRegex "[\\w]*son")   // <- This does not exist
Run Code Online (Sandbox Code Playgroud)

如果相关:我使用 Postgres。

Ric*_*way 7

(此答案遵循Slick 中的问题:如何将 SQL LIKE 语句与 SQL IN 语句结合起来

尽管 Slick 不支持~*开箱即用的运算符,但您可以自己添加。这将为您提供一种使用Slick 查询的提升嵌入样式执行查询的方法。

为此,您可以使用SimpleExpression构建器。关于它的文档并不多,但起点是参考手册的标量数据库函数页面。

我们想要做的是按照以下方式编写一个方法:

def find(names: Seq[String]): DBIO[Seq[String]] = {
  val pattern = names.mkString("|")
  users.filter(_.lastName regexLike pattern).map(_.lastName).result
}
Run Code Online (Sandbox Code Playgroud)

为了获得regexLike我们可以使用丰富(增强,“皮条客”)字符串列的regexLike方法:

implicit class RegexLikeOps(s: Rep[String]) {
  def regexLike(p: Rep[String]): Rep[Boolean] = {
    val expr = SimpleExpression.binary[String,String,Boolean] { (s, p, qb) =>
      qb.expr(s)
      qb.sqlBuilder += " ~* "
      qb.expr(p)
    }
    expr.apply(s,p)
  }
}
Run Code Online (Sandbox Code Playgroud)

implicit class部分是允许编译器在RegexLikeOps任何时候构造类,它Rep[String]调用一个Rep[String]没有的方法(即,当regexLike被要求时)。

我们的regexLike方法将另一个Rep[String]参数作为模式,然后使用SimpleExpressionbuilder 安全地构建我们想要使用的 SQL。

把它们放在一起,我们可以写:

val program = for {
  _ <- users.schema.create
  _ <- users ++= User("foo") :: User("baz") :: User("bar") :: Nil
  result <- find( Seq("baz","bar") )
} yield result

println( Await.result(db.run(program), 2.seconds) )
Run Code Online (Sandbox Code Playgroud)

生成的 SQL(在我的 H2 测试中)是:

select "last_name" from "app_user" where "last_name" ~* 'baz|bar'
Run Code Online (Sandbox Code Playgroud)

完整代码为:https : //github.com/d6y/so46199828