2016-11-29 30 views
0

給予一定的一UserRepository斯卡拉 - 篩選失敗一定條件

class UserRepository { 

    val collection = Mongo.connect("users") 

    def findBy(key: String, value: String): Future[Option[User]] = { 
    collection.flatMap(
     _.find(document(key -> value)).one[User] 
    ) 
    } 
} 

我想寫一個login方法:

def login(email: String, password: String): Future[Option[User]] = { 
    import scala.concurrent.ExecutionContext.Implicits.global 

    repo.findBy("email", email) 
    // .filter { user => BCrypt.checkpw(password, user.password) } 
} 

如何將我寫的findBy到結果的映射如果他們測試失敗BCrypt.checkpw(password, user.password),將所有Some(user)的變成None?我能做些什麼來改變None失敗的Some

+0

你就不能使用您註釋掉'filter'法:在它的簽名(Option[User])你可能想這已經說明?它有什麼問題? – marstran

+0

直接進入過濾器的問題是該值是'Some'或'None',因此只需執行'BCrypt.checkpw(password,user.password)'拋出: '編譯錯誤[value password is不是Option [authentication.User]]的成員' – danbroooks

+0

當然,我可以在過濾器內部做一個匹配,我只是想知道是否有什麼比模式匹配更好用在這裏?感覺有點奇怪,執行模式匹配,然後只是返回另一個「選項」(這可能只是我的思路,在這種情況下這是一個完全合理的事情) – danbroooks

回答

2

使用收集並使用模式匹配警衛來檢查用戶。如果用戶無法再返回無

findBy(key, value).collect { 
    case Some(user) if ! BCrypt.checkpw(password, user.password) => None 
} 

建議

這將是很好的收集用戶滿足條件這樣你的最終輸出類型將Future[user]而不是Future[Option[User]]。當然,在收集您的Future[Option[User]]之後,將會包含Some(user),其中user是有效的用戶。

findBy(key, value).collect { 
    case Some(user) if BCrypt.checkpw(password, user.password) => user 
} 

該行給出唯一有效的用戶和最終的類型將是Future[User]而不是Future[Option[User]]

+0

如果沒有用戶匹配'findBy',會發生什麼? – danbroooks

+0

@danbroooks它會給你'沒有' – 2016-11-29 16:16:19

+0

@danbroooks'未來'將有'沒有'。正如第一種情況和第二種情況一樣,您將得到'java.util.NoSuchElementException'。當然,異常將被包裹在未來中。選擇你想要使用的。 – pamu

3

您需要映射在FutureSome改變其值設置爲None。過濾器的調用需要進入傳遞給map函數的函數內部。試試這個:

def login(email: String, password: String): Future[Option[User]] = { 
    import scala.concurrent.ExecutionContext.Implicits.global 

    repo.findBy("email", email) 
     .map { userOpt => userOpt.filter(user => BCrypt.checkpw(password, user.password)) } 
} 
+1

f。克的答案是清潔的,但。至少這表明你最初的嘗試有什麼問題。 – marstran

3

你可能不希望在Futurefilter/collect,因爲你會得到一個失敗的未來(有例外),然後你需要.recover等。由於你的操作結果

repo.findBy("email", email).map { userOpt => 
    val maybeUser1 = userOpt.filter { user => BCrypt.checkpw(password, user.password) } 

    // or like this: 
    // longer form, if more than one options or whatever 
    val maybeUser2 = for { 
    user <- userOpt 
    if(BCrypt.checkpw(password, user.password)) 
    } yield user 
} 
+0

有了這個,我得到'類型不匹配; found:scala.concurrent.Future [Option [authentication.User]] required:Option [authentication.User]' – danbroooks

+0

然後'findBy(「email」,email)。** flatMap **'? xD –

+0

然後我得到'類型不匹配; found:Option [authentication.User] required:scala.concurrent.Future [?]':/ – danbroooks