使用Scala油滑对于干善高阶函数(Higher order functions with Scal

2019-08-08 03:27发布

我有一个想法Scala的油滑我的数据访问层应该如何的样子,但我不知道是否真的有可能。

假设我有一个有一个像ID,电子邮件,密码等常用的字段中输入用户表

  object Users extends Table[(String, String, Option[String], Boolean)]("User") {
    def id = column[String]("id", O.PrimaryKey)
    def email = column[String]("email")
    def password = column[String]("password")
    def active = column[Boolean]("active")
    def * = id ~ email ~ password.? ~ active
  }

我想查询他们以不同的方式,目前的丑陋的方式就是有一个新的数据库会话,做的理解,然后做不同的if语句来达到我想要的。

  def getUser(email: String, password: String): Option[User] = {
    database withSession { implicit session: Session =>
      val queryUser = (for {
        user <- Users
          if user.email === email &&
             user.password === password &&
             user.active === true
      } //yield and map to user class, etc...
  }

  def getUser(identifier: String): Option[User] = {
    database withSession { implicit session: Session =>
      val queryUser = (for {
        user <- Users
        if user.id === identifier &&
           user.active === true
      } //yield and map to user class, etc...
  }

我宁愿是有用于查询的私有方法,然后沿的线条定义查询的公共方法

type UserQuery = User => Boolean

private def getUserByQuery(whereQuery: UserQuery): Option[User] = {
  database withSession { implicit session: Session =>
      val queryUser = (for {
        user <- Users
          somehow run whereQuery here to filter
      } // yield and boring stuff
  }

def getUserByEmailAndPassword(email, pass){ ... define by query and call getUserByQuery ...}

getUserById(id){….}

getUserByFoo{….} 

通过这种方式,查询逻辑封装在相关的公共职能和实际查询和映射到用户对象是可重复使用的功能,其他人不需要去关注。

我的问题是试图重构“其中”比特就是到功能,我可以绕过。 试图做这样的事情在的IntelliJ选择它们并使用重构导致一些非常疯狂的打字怎么回事。

有没有人有他们可以做展示接近我所要达到的任何例子吗?

Answer 1:

1)在一个DEF包裹查询装置在每次请求中的查询语句是重新产生的,并且,由于查询参数不结合,不准备语句被传递到底层DBMS。

2)你不趁着组成

相反,如果定义参数化查询瓦尔斯是高清查询包装打电话,你可以得到两全其美。

val uBase = for{
  u  <- Users
  ur <- UserRoles if u.id is ur.UserID
} yield (u,ur)

// composition: generates prepared statement one time, on startup
val byRole = for{ roleGroup <- Parameters[String]
  (u,ur) <- uBase
  r <- Roles if(r.roleGroup is roleGroup) && (r.id is ur.roleID)
} yield u

def findByRole(roleGroup: RoleGroup): List[User] = {
  db withSession { implicit ss:SS=>
    byRole(roleGroup.toString).list
  }
}

如果你需要一个单一的财产一次性发现者,使用方法:

val byBar = Foo.createFinderBy(_.bar)
val byBaz = Foo.createFinderBy(_.baz)

不记得在那里,也许对SO,或漂亮的用户群,但我没有看到允许多个绑定参数,可以基本上是一个非常有创意的解决方案createFinderBy类固醇。 虽然不是那么有用我,作为溶液限于单个映射器/表对象。

在撰写的内涵任何率似乎做你想要做的事。



Answer 2:

我最近做类似的东西,要做到这一点,可以下面,写这需要一个谓语一般选择方法的一种方式

def select(where: Users.type => Column[Boolean]): Option[User] = {
    database withSession { implicit session: Session =>
      val queryUser = (for {
        user <- Users where(user)

      } //yield and map to user class, etc...
  }

and then write the method which passes the actual predicate as a higher order function

def getUserByEmail(email:String):Option[User]={
      select((u: Users.type) => u.*._2 === email)
}
similarly 

def getActiveUserByEmail(email:String):Option[User]={
     select((u: Users.type) => u.*._2 === email && u.*._4 === true)
}


文章来源: Higher order functions with Scala Slick for DRY goodness