Tihomir Manushev
Tihomir Manushev

Reputation: 106

Chaining two futures in Swift Vapor framework

I have this function that checks if an username already exists in the database during registration (REST API). If the username already exists, a nice error message is displayed. Now I want to add the same check for the email, with a nice error message and a check if both username and email already exists, again with it's own nice error message.

I don't have much experience with async coding and I don't understand how chain the two futures.

This is the main function:

fileprivate func create(req: Request) throws -> EventLoopFuture<NewSession> {
        try UserSignup.validate(content: req)
        let userSignup = try req.content.decode(UserSignup.self)
        let user = try User.create(from: userSignup)
        var token: Token!
        
        return checkIfUserExists(userSignup.username, req: req).flatMap { exists in
            guard !exists else {
                return req.eventLoop.future(error: UserError.usernameTaken)
            }
            return user.save(on: req.db)
        }.flatMap {
            guard let newToken = try? user.createToken(source: .signup) else {
                return req.eventLoop.future(error: Abort(.internalServerError))
            }
            token = newToken
            
            return token.save(on: req.db)
        }.flatMapThrowing {
            NewSession(token: token.value, user: try user.asPublic())
        }
    }

This is the checkIfUserExists function:

    private func checkIfUserExists(_ username: String, req: Request) -> EventLoopFuture<Bool> {
        User.query(on: req.db)
            .filter(\.$username == username)
            .first()
            .map { $0 != nil }
    }

This is the checkIfEmailExists function:

    private func checkIfEmailExists(_ email: String, req: Request) -> EventLoopFuture<Bool> {
        User.query(on: req.db)
            .filter(\.$email == email)
            .first()
            .map { $0 != nil }
    }

I've tried if-else, tried .add() and other weird stuff but I can't get it to work. Also I need to keep this syntax and not using the async/await syntax.

Upvotes: 1

Views: 73

Answers (1)

Nick
Nick

Reputation: 5190

Modify your query to include a group:

query.group(.or) { group in
    group.filter(\User.$username == username).filter(\User.$email == email)
}

Upvotes: 1

Related Questions