Joseph Simeone
Joseph Simeone

Reputation: 11

Error when attempting to convert EventLoopFuture<Type> to Type

I'm new to coding in general and the concept of futures especially so patience would be appreciated! The goal of the following function is to check whether or not an account exists in a PostgreSQL database. If it does, return an empty UUID; if no account exists, create a new one and return its UUID. When I try to run my code, the error Cannot convert return expression of type 'EventLoopFuture<Account.idOut>' to return type 'Account.idOut' appears next to the line .map { Account.idOut(id: account.id!) }. I've looked around here already and can't seem to find any solution to this problem. Any help would be appreciated, thanks!!

func newAccount(req: Request) throws -> EventLoopFuture<Account.idOut> {
        let input = try req.content.decode(Account.postAccount.self)
        
        //check to see if account already exists
        return Account.query(on: req.db)
            .filter(\.$email == input.email)
            .first().map { checkAccount in
                if checkAccount == nil {
                    let id = UUID()
                    let account = Account(id: id, fullName: input.fullName, email: input.email, password: input.password, type: input.type)
                    return account.save(on: req.db)
                        .map { Account.idOut(id: account.id!) }
                } else {
                    return Account.idOut(id: UUID("00000000-0000-0000-0000-000000000000")!)
                }
            }
    }

Upvotes: 0

Views: 678

Answers (1)

0xTim
0xTim

Reputation: 5585

In short, you need to return the same type to satisfy the compiler. This can definitely get a bit confusing with an if/else like yours where one returns a future and one doesn't. The way around it, is to return a future for both like so:

    func newAccount(req: Request) throws -> EventLoopFuture<Account.idOut> {
        let input = try req.content.decode(Account.postAccount.self)
        
        //check to see if account already exists
        return Account.query(on: req.db)
            .filter(\.$email == input.email)
            .first().flatMap { checkAccount in
                if checkAccount == nil {
                    let id = UUID()
                    let account = Account(id: id, fullName: input.fullName, email: input.email, password: input.password, type: input.type)
                    return account.create(on: req.db)
                        .map { Account.idOut(id: account.id!) }
                } else {
                    return req.eventLoop.future(Account.idOut(id: UUID("00000000-0000-0000-0000-000000000000")!))
                }
            }
    }

Important things to note:

  • I changed the first map to a flatMap since you're returning a future inside
  • I used create instead of save for the save operation as you're providing an ID and this forces Fluent to create the model. (Fluent will usually set the ID for you)
  • I wrapped the account in req.eventLoop.future - this returns EventLoopFuture<Account.idOut> which satisfies the compiler

Upvotes: 2

Related Questions