如何在蒸气中将EventLoopF​​uture <Type>数组映射到EventLoopF​​uture <OtherType>数组

时间:2019-09-02 05:44:14

标签: swift future vapor

我有一个Vapor后端,我为此编写了一些测试。

测试代码如下:

    func testFollowUser() throws {
        user = try user.save(on: conn).wait()

        let userToFollow = try User(firstName: "Friedrich", lastName: "Nietzsche", email: "f.nietzsche@gmail.com", passwordHash: User.TestValues.passwordHash).save(on: conn).wait()

        let req = UserListRequest(ids: [userToFollow.id!])

        XCTAssert(try user.followers.query(on: conn).count().wait() == 0)
        XCTAssert(try userToFollow.followees.query(on: conn).count().wait() == 0)

        let res = try app.sendRequest(to: "/me/following", method: .PUT, body: req, isLoggedInRequest: true)

        //sleep(4)

        XCTAssert(res.http.status == .noContent, "Returned \(res.http.status)")
        XCTAssert(try user.followers.query(on: conn).count().wait() == 1)
        XCTAssert(try userToFollow.followees.query(on: conn).count().wait() == 1)
        XCTAssert(try user.followers.query(on: conn).first().wait()?.id == userToFollow.id)

        _ = userToFollow.delete(on: conn)
    }

(sendRequest(to:method:body:isLoggedInRequest)使用.wait()等待请求完成)

经过测试的函数beeing看起来像这样:

    func followUsers(_ req: Request) throws -> Future<HTTPStatus> {
        let user = try req.requireAuthenticated(User.self)
        return try req.content.decode(UserListRequest.self).flatMap { userListRequest -> EventLoopFuture<HTTPStatus> in
            userListRequest.ids.map { idToFollow -> EventLoopFuture<User?> in
                return User.find(idToFollow, on: req)
            }.flatten(on: req).map {
                maybeUsersToFollow -> Future<[FollowPivot]> in
                var futureArray: [Future<FollowPivot>] = []
                for maybeUserToFollow in maybeUsersToFollow {
                    if let userToFollow = maybeUserToFollow {
                        let pivot = try FollowPivot(user, userToFollow).save(on: req)
                        futureArray.append(pivot)
                    }
                }
                return futureArray.flatten(on: req)
            }.transform(to: req.future(HTTPStatus(statusCode: 204)))
        }
    }

我执行测试时失败。如果在测试方法中添加“ sleep(4)”,则测试通过。因此,我认为执行XCTAssert时数据库中的Postgres操作没有完成。

我将上面的功能代码更改为:

    func followUsers(_ req: Request) throws -> Future<HTTPStatus> {
        let user = try req.requireAuthenticated(User.self)
        return try req.content.decode(UserListRequest.self).flatMap { userListRequest -> EventLoopFuture<HTTPStatus> in
            userListRequest.ids.map { idToFollow -> EventLoopFuture<User?> in
                return User.find(idToFollow, on: req)
            }.map { maybeUserToFollowFuture -> Future<Void> in
                maybeUserToFollowFuture.then {
                    maybeUserToFollow in
                    if let userToFollow = maybeUserToFollow {
                        do {
                            return try FollowPivot(user, userToFollow)
                                .save(on: req)
                                .transform(to: req.future())
                        } catch {}
                    }
                    return req.future()
                }
            }.flatten(on: req)
            .transform(to: req.future(HTTPStatus(statusCode: 204)))
        }
    }

现在测试成功了,但是我认为代码很糟糕。

我如何正确处理[EventLoopFuture<Type>][EventLoopFuture<OtherType>],同时保证仅在满足数组中的所有期货之后才执行后续的地图转换操作? 为什么我的第一个followUser(on:)无法正常工作?我是否需要明确的.then()操作来保证实现?

0 个答案:

没有答案