Search code examples
swiftfluentvaporvapor-fluent

In Fluent / Vapor 4, how do I filter a list based on a foreign key?


so I have models names Organization, User, and App. Apps and Users both belong to organizations.

final class Organization: Model, Content {
    static let schema = "organizations"

    @ID(key: .id)
    var id: UUID?

    @Field(key: "name")
    var name: String
    
    @Children(for: \.$organization)
    var users: [User]
}

final class App: Model, Content {
    static let schema = "apps"

    @ID(key: .id)
    var id: UUID?

    @Field(key: "name")
    var name: String

    @Parent(key: "organization_id")
    var organization: Organization
}


final class User: Model, Content {
    static let schema = "users"

    @ID(key: .id)
    var id: UUID?

    @Field(key: "email")
    var email: String

    @Field(key: "password_hash")
    var passwordHash: String
    
    @Parent(key: "organization_id")
    var organization: Organization
}

Now, basically what I want to do is, given a user, I want to get all the Apps that belong to that user's organization.

I can get the user from my auth system, but then all I have is this query:

let user = try req.auth.require(User.self)
return App.query(on: req.db).filter(\.$organization.id == user.$organization.id).all()

This fails with the error message Operator function '==' requires that 'UUID' conform to 'QueryableProperty'.

What should I do instead?


Solution

  • You need to provide the key path to the projected value of a property wrapper you want to filter on, instead of the value itself. So as you discovered it needs to be:

    .filter(\.$organization.$id == user.$organization.id)
    

    The reason why you have to use the property wrapper's projected value instead of just the property itself is because the property wrapper contains the information it needs to perform the query (like the column name) which wouldn't be available with just the property