Search code examples
iosswiftpromisepromisekit

PromiseKit 6.0 migration


I have decided to upgrade PromiseKit pod form 4.5.x to 6.x.x in my project. During migration process I met an problem which I not 100% sure I solved it in proper way.

Take a look on my sample code from PromiseKit 4.5:

func fetchSettings(forAnimalsGuids animalsGuids: [String]) -> Promise<[JSON]> {
    if animalsGuids.isEmpty {
        return .value([])
    }

    let packageSize = 100
    let animalsPackages = animalsGuids.chunked(chunkSize: packageSize)

    return when(fulfilled: animalsPackages.map({ animalsPackage -> Promise<[JSON]> in
        let predicates: [GatewayRequestFactoryHelper.Predicate] = animalsPackage.map({ .atomic(.equal("Animal.ObjectGuid", .string($0))) })
        let predicate: GatewayRequestFactoryHelper.Predicate? = !predicates.isEmpty ? .or(predicates) : nil

        return gatewayConnector.fetchObjects(type: AnimalMilkSetting.self, predicate: predicate)
    }))
    .then { result in
        Promise(value: Array(result.joined()))
    }
}

In a line with Promise(value: Array(result.joined())) I got an error:

Argument labels '(value:)' do not match any available overloads

According to PromiseKit migration guide return Promise(value: foo) have beed replaced with: return .value(foo), so I refactored my code:

func fetchAnimal(forAnimalsGuids animalsGuids: [String]) -> Promise<[JSON]> {
    if animalsGuids.isEmpty {
        return .value([])
    }

    let packageSize = 100
    let animalsPackages = animalsGuids.chunked(chunkSize: packageSize)

    return when(fulfilled: animalsPackages.map({ animalsPackage -> Promise<[JSON]> in
        let predicates: [GatewayRequestFactoryHelper.Predicate] = animalsPackage.map({ .atomic(.equal("Animal.ObjectGuid", .string($0))) })
        let predicate: GatewayRequestFactoryHelper.Predicate? = !predicates.isEmpty ? .or(predicates) : nil

        return gatewayConnector.fetchObjects(type: AnimalMilkSetting.self, predicate: predicate)
    }))
    .then { result in
        .value(Array(result.joined()))
//      Promise(value: Array(result.joined()))
    }
}

It did not help. Compile showed an error message:

Cannot convert return expression of type 'Promise<_.T>' to return type 'Promise<[JSON]>'

I made some tweaks and finally find a solution which is accepted my compiler:

func fetchAnimal(forAnimalsGuids animalsGuids: [String]) -> Promise<[JSON]> {
    if animalsGuids.isEmpty {
        return .value([])
    }

    let packageSize = 100
    let animalsPackages = animalsGuids.chunked(chunkSize: packageSize)

    return when(fulfilled: animalsPackages.map({ animalsPackage -> Promise<[JSON]> in
        let predicates: [GatewayRequestFactoryHelper.Predicate] = animalsPackage.map({ .atomic(.equal("Animal.ObjectGuid", .string($0))) })
        let predicate: GatewayRequestFactoryHelper.Predicate? = !predicates.isEmpty ? .or(predicates) : nil

        return gatewayConnector.fetchObjects(type: AnimalMilkSetting.self, predicate: predicate)
    }))
    .then { result in
        Promise { $0.fulfill(Array(result.joined())) }
    }
}

Could you give me an answer. Did I migrate it in a proper way? Way .value(Array(result.joined())) does not work?


Solution

  • I think I found an answer by myself. I used map introduced in PromiseKit 6. From doc:

    map is fed the previous promise value and requires you return a non-promise, ie. a value.

    So:

    func fetchAnimal(forAnimalsGuids animalsGuids: [String]) -> Promise<[JSON]> {
        if animalsGuids.isEmpty {
            return .value([])
        }
    
        let packageSize = 100
        let animalsPackages = animalsGuids.chunked(chunkSize: packageSize)
    
        return when(fulfilled: animalsPackages.map({ animalsPackage -> Promise<[JSON]> in
            let predicates: [GatewayRequestFactoryHelper.Predicate] = animalsPackage.map({ .atomic(.equal("Animal.ObjectGuid", .string($0))) })
            let predicate: GatewayRequestFactoryHelper.Predicate? = !predicates.isEmpty ? .or(predicates) : nil
    
            return gatewayConnector.fetchObjects(type: AnimalMilkSetting.self, predicate: predicate)
        }))
        .map {
            Array($0.joined())
        }
    }
    

    I think this solution is better than wrapping result in another Promise. Simply and Swifty.