代码之家  ›  专栏  ›  技术社区  ›  Chandler De Angelis

等待异步任务在Vapor中的请求中完成

  •  0
  • Chandler De Angelis  · 技术社区  · 6 年前

    我正在使用服务器端swift框架Vapor编写一个API。我的模型很简单。我有一个 Workout 表,它与 Circuit 表,它与 Exercise

    {
        ...
        circuits: [{
            ...,
            exercises: [{
                "title": ...
            }, {
                "title": ...
            }]
        }, {
            ...,
            exercises: [{
                "title": ...
            }, {
                "title": ...
            }]
        }]
    }
    

    我遇到的问题是,当用户在多个回路中进行相同的练习时,会创建重复的练习。我在创建一个新的练习之前查询数据库,但是看起来保存都是异步进行的,这使得我无法在保存一个新的练习之前在数据库中检测到具有相同id/标题的现有练习。这是我的密码:

    private func saveExercise(on conn: DatabaseConnectable, with content: WorkoutCreateExerciseContent, for authUser: User) throws -> Future<Exercise> {
    
            if let exerciseId: UUID = content.id {
    
                return Exercise.find(exerciseId, on: conn)
                    .unwrap(or: Abort(.badRequest, reason: "No exercise for id: \(exerciseId.uuidString)"))
    
            } else if let title: String = content.title, let isPublicallyVisible: Bool = content.isPublicallyVisible {
    
                return Exercise.query(on: conn).filter(\.title == title).filter(\.directions == content.directions).first().flatMap({ (possibleMatchingExercise: Exercise?) -> Future<Exercise> in
    
                    if let matchingExercise: Exercise = possibleMatchingExercise {
    
                        return conn.future(matchingExercise)
    
                    } else {
                        print("xxx Found no match for \(title)")
                        let newExercise: Exercise = Exercise(
                            title: title,
                            directions: content.directions,
                            isPublicallyVisible: isPublicallyVisible
                        )
                        newExercise.userId = authUser.id
                        return newExercise.save(on: conn)
    
                    }
    
                })
    
            } else {
    
                throw Abort(.badRequest, reason: """
                    Bad data for exercise. Expecting either of the following:
                    {
                        /"id/": /"some id/"
                    }
                    or
                    {
                        /"title/": /"some title/"
                        /"directions/": /"(optional)/",
                        /"isPublicallyVisible/": false
                    }
                    id takes priority over other properties.
                """)
            }
    
        }
    
        private func saveCircuit(on conn: DatabaseConnectable, with content: CircuitCreateContent, order: Int, workoutId: UUID, authUser: User) throws -> Future<Circuit> {
    
            return try content.exercises.map({ (exerciseContent: WorkoutCreateExerciseContent) throws -> Future<Exercise> in
    
                let createdExercise: Future<Exercise> = try self.saveExercise(
                    on: conn,
                    with: exerciseContent,
                    for: authUser
                )
    
                return createdExercise
    
            })
            .flatten(on: conn)
            .flatMap({ (exercises: [Exercise]) -> Future<Circuit> in
    
                let circuit: Circuit = Circuit(
                    workoutId: workoutId,
                    order: order,
                    exerciseDuration: content.exerciseDuration,
                    restDuration: content.restDuration,
                    exerciseIDs: exercises.compactMap({ $0.id })
                )
    
                return circuit.save(on: conn)
    
            })
    
        }
    
        func saveWorkout(_ conn: DatabaseConnectable,  _ authentiatedUser: User, _ content: WorkoutCreateContent) throws -> Future<Workout> {
    
            let workout: Workout = content.makeWorkout()
    
            workout.userId = authentiatedUser.id
    
            // First save the exercises
    
            let createdWorkout: Future<Workout> = workout.save(on: conn).flatMap({ (savedWorkout: Workout) -> Future<Workout> in
    
                let createdCircuits: Future<[Circuit]> = try content.circuits.enumerated().map({ (order: Int, circuitContent: CircuitCreateContent) throws -> Future<Circuit> in
    
                    let createdCircuit: Future<Circuit> = try self.saveCircuit(
                        on: conn, with: circuitContent,
                        order: order,
                        workoutId: savedWorkout.id!,
                        authUser: authentiatedUser
                    )
    
                    return createdCircuit
    
                })
                .flatten(on: conn)
    
                return createdCircuits.then({ _ -> Future<Workout> in
                    return conn.future(savedWorkout)
                })
    
            })
    
            return createdWorkout
    
        }
    

    有人看到我在这里遗漏了什么吗?有没有办法等一等 Future 在开始新的工作之前完成 未来

    0 回复  |  直到 6 年前
        1
  •  2
  •   MomoNjf    5 年前

    假设我们有两种想象的方法 Future<>

    func randomUInt() -> Future<UInt> { ... }
    func multiply(value: UInt, by multiplier: UInt) -> Future<UInt> { ... }
    

    我们想把一个随机数乘以5,但如果随机数是0或1,我们就抛出错误。因此,在调用 multiply(value: ,by: )

    let result: Future<UInt> = randomUInt().flatMap { (value) -> Future<UInt> in
        guard value > 1 else { throw YourError }
        return multiply(value: value, by: 5)
    }
    
    推荐文章