Kitura / Swift-Kuery-ORM

An ORM for Swift, built on Codable
Apache License 2.0
212 stars 30 forks source link

Upgrading to Swift-Kuery-ORM 0.4.X and Swift-Kuery-PostgreSQL 2.X breaks application #91

Closed fwgreen closed 5 years ago

fwgreen commented 5 years ago

I have working applications on both Ubuntu and macOS that stopped working after upgrading. There are no errors or warnings. It seems as if all queries are coming back empty from the database. The database server reports no errors at its end. Downgrading to Swift-Kuery-ORM 0.3.1 and Swift-Kuery-PostgreSQL 1.2.0 resolves the problem.

kilnerm commented 5 years ago

@fwgreen, Could you show me some sample code that isn't working as expected?

My immediate hunch is that this relates to the fact the ORM API will now behave in an asynchronous fashion since the update to SwiftKuery 3.0.

fwgreen commented 5 years ago

@kilnerm Trying to create a minimal working example revealed that the problem is at my end. I have a generic repository which seems to only work in synchronous mode.

import SwiftKueryORM
import LoggerAPI

protocol AbstractRepository {
    associatedtype Entity : Model
}

extension AbstractRepository {
    func list<Q : QueryParams>(filter: Q) -> [Entity] {
        var entities: [Entity] = []
        Entity.findAll(matching: filter) { results, error in 
            if let error = error { Log.error("Error: \(error)") }
            if let results = results { entities = results }
        }
        return entities
    }

    func list() -> [Entity] {
        var entities: [Entity] = []
        Entity.findAll { results, error in 
            if let error = error { Log.error("Error: \(error)") }
            if let results = results { entities = results }
        }
        return entities
    }

    func find(id: Int) -> Entity? {
        var entity: Entity?
        Entity.find(id: id) { result, error in 
            if let error = error { Log.error("Error: \(error)") }
            if let result = result { entity = result }
        }
        return entity
    }
}

class Repository<E : Model> : AbstractRepository {
    typealias Entity = E
}
kilnerm commented 5 years ago

@fwgreen, Looking at the code above you will need to move your return entities calls inside the closure you pass into the Entity.find* functions, for example:

func list() -> [Entity] {
        var entities: [Entity] = []
        Entity.findAll { results, error in 
            if let error = error { Log.error("Error: \(error)") }
            if let results = results { entities = results }
            return entities
        }
    }

The ORM methods will now behave asynchronously so the calling thread will drop through to the return call at the moment the findAll call make an underlying call to the database.

Let me know if you have any other issues after making the changes.

fwgreen commented 5 years ago

@kilnerm Thanks for your help! Sadly, I couldn't get the approach you outlined to work (I'm a novice at Swift), but it inspired a work around that allows me to keep my generic repository: Flip the whole thing on its head and pass the view into the repository:

func list(_ view: @escaping (_: [Entity]) -> Void) {
    Entity.findAll { results, error in 
        if let error = error { Log.error("Error: \(error)") }
        if let results = results { view(results) }
    }
}