plarson/fluent-postgis

Not possible to filter with optional value

rabc opened this issue · 1 comments

rabc commented

Hi,

I have a table where the GeographicPoint2D property is optional and it is not possible to use filterGeometryDistanceWithin with this property without force-unwrapping it. I made a unit test to showcase this situation:

func testOptionalLocation() throws {
    struct UserGeographicLocation: PostgreSQLModel, Migration {
        var id: Int?
        var name: String
        var location: GeographicPoint2D?
    }
    let conn = try benchmarker.pool.requestConnection().wait()
    conn.logger = DatabaseLogger(database: .psql, handler: PrintLogHandler())
    defer { benchmarker.pool.releaseConnection(conn) }

    try UserGeographicLocation.prepare(on: conn).wait()
    defer { try! UserGeographicLocation.revert(on: conn).wait() }

    let point: GeographicPoint2D = GeographicPoint2D(longitude: 1, latitude: 2)

    var user = UserGeographicLocation(id: nil, name: "My User", location: point)
    user = try user.save(on: conn).wait()

    // Crash:
    // Fatal error: Unexpectedly found nil while unwrapping an Optional value
    // without the `!`, it will not build
    let all = try UserGeographicLocation.query(on: conn).filterGeometryDistanceWithin(\UserGeographicLocation.location!, point, 1000).all().wait()
    XCTAssertEqual(all.count, 1)
}

I tried to look the code to find a solution, but couldn't find any way to workaround or fix it.

rabc commented

Found a solution: use Database.QueryField. Here is the test without errors:

func testOptionalLocation() throws {
    struct UserGeographicLocation: PostgreSQLModel, Migration {
        var id: Int?
        var name: String
        var location: GeographicPoint2D?
    }
    let conn = try benchmarker.pool.requestConnection().wait()
    conn.logger = DatabaseLogger(database: .psql, handler: PrintLogHandler())
    defer { benchmarker.pool.releaseConnection(conn) }

    try UserGeographicLocation.prepare(on: conn).wait()
    defer { try! UserGeographicLocation.revert(on: conn).wait() }

    let point: GeographicPoint2D = GeographicPoint2D(longitude: 1, latitude: 2)

    var user = UserGeographicLocation(id: nil, name: "My User", location: point)
    user = try user.save(on: conn).wait()

    let all = try UserGeographicLocation.query(on: conn).filterGeometryDistanceWithin(.keyPath(\UserGeographicLocation.location),
                                                                                      PostgreSQLDatabase.queryFilterValueGeometry(point),
                                                                                      1000).all().wait()

    XCTAssertEqual(all.count, 1)
}