vapor / fluent-postgres-driver

🐘 PostgreSQL driver for Fluent.
MIT License
149 stars 53 forks source link

Join on tables with different enum fields with same name can cause a crash #94

Closed FredericRuaudel closed 4 years ago

FredericRuaudel commented 6 years ago

FluentPostgreSQL version 1.0.0 PostgreSQL version 1.0.1 Vapor Core version: 3.4.2 (see Package.resolved in joined example project for other module versions)

I've recently stumble upon a bug while joining two tables that both have a PostgreSQLEnum field with the same name. And it causes a weird bug that was either:

usually, it crashes half of the times and succeeds the other half with a perfect 1 for 1 rate

So to show the bug, I've created a simple sample project based on Todo template (see attached zip) with this simple DB schema to show the problem. You need to create a PG database named joinenumbug to make it runs and runs the tests of the app to get the bug.

We have a Todo table with a status field of type Enum TodoStatus and a Attachment table with also a status field but of another type Enum AttachmentStatus and they are linked via the Todo's attachmentId foreignKey.

schema_bugenum

So when I perform a join between this two tables, the result has two columns with the same name but with different data types inside:

2018-08-30 at 17 29

and it confuses the decoder which is trying to pass all the status values to the RawRepresentable decodable init method and as the value doesn't matches any value, it throws an error in the best scenario

You can also see that clearly if you redefined the decodable init for the enum like this:

extension AttachmentStatus {
    public init?(rawValue: String) {
        print("############### --- \(rawValue)")
        if (rawValue == "new") {
            self = .new
        }
        else if (rawValue == "old") {
            self = .old
        }
        else {
            return nil
        }
    }
}

it will display:

############### --- old
############### --- new
############### --- done
############### --- doing

showing the problem.

The only workaround I've found is to rename one of the two fields with a different name but it's not a really satisfying solution 😉

Hope you can help!

Thanks in advance!

JoinEnumBug.zip

tanner0101 commented 4 years ago

This was happening because Postgres' table name cache is outdated and it is unable to resolve the difference between the two columns. After running migrations you should call:

try! app.requestCachedConnection(to: .psql).wait()

This will reload postgres' table name cache allowing both status fields to be distinguishable.