Home > Back-end >  Vapor 4, How to filter by Foreign Key?
Vapor 4, How to filter by Foreign Key?

Time:06-27

I have two models (UserModel and UserTokenModel)

UserTokenModel has a ForeignKey that indicates UserModel.

Here is my code. I tried to filter by userModel's Id on UserTokenModel but I got an error.

Operator function '==' requires that 'UUID' conform to 'QueryableProperty'

if let user = try await UserModel.query(on: req.db).filter(\.$email == request.email).first() {
    //Compile Error: Operator function '==' requires that 'UUID' conform to 'QueryableProperty'
    let userToken = try await UserTokenModel.query(on: req.db)
    .filter(\.$user.id == user.$id).first()
}

Here is definition of Models

final class UserModel: Model {
    static let schema = "user_users"
    
    struct FieldKeys {
        static var email: FieldKey { "email" }
        static var password: FieldKey { "password" }
        static var appleId: FieldKey { "appleId" }
        static var givenName: FieldKey { "givenName" }
        static var familyName: FieldKey { "familyName" }
        static var userName: FieldKey { "userName" }
    }
    
    //MARK:- fields
    @ID() var id: UUID?
    @Field(key: FieldKeys.email) var email: String
    @Field(key: FieldKeys.password) var password: String
    @Field(key: FieldKeys.appleId) var appleId: String?
    @Field(key: FieldKeys.givenName) var givenName: String?
    @Field(key: FieldKeys.familyName) var familyName: String?
    @Field(key: FieldKeys.userName) var userName: String?
    
    init() {}
    
    init(id: UserModel.IDValue? = nil,
         email: String,
         password: String,
         appleId: String? = nil,
         givenName: String? = nil,
         familyName: String? = nil,
         userName: String? = nil
    ) {
        self.id = id
        self.email = email
        self.password = password
        self.appleId = appleId
        self.givenName = givenName
        self.familyName = familyName
        self.userName = userName
    }
}

UserTokenModel

final class UserTokenModel: Model {
    static let schema = "user_tokens"
    
    struct FieldKeys {
        static var value: FieldKey { "value" }
        static var userId: FieldKey { "user_id" }
    }
    
    //MARK:- fields
    
    @ID() var id: UUID?
    @Field(key: FieldKeys.value) var value: String
    @Parent(key: FieldKeys.userId) var user: UserModel
    
    init() {}
    init(
        id: UserTokenModel.IDValue? = nil,
        value: String,
        userId: UserModel.IDValue
    ) {
        self.id = id
        self.value = value
        $user.id = userId
    }
}

CodePudding user response:

You need to change your code to:

if let user = try await UserModel.query(on: req.db).filter(\.$email == request.email).first() {
    guard let userId = user.id
    else { throw SomeError() }
    //Compile Error: Operator function '==' requires that 'UUID' conform to 'QueryableProperty'
    let userToken = try await UserTokenModel.query(on: req.db)
    .filter(\.$user.$id == userId).first()
}

The QueryableProperty error is due to you not putting in the $ in front of the id in the LHS of the filter. If you fixed this, you would then have got an error about the user.id property being Optional. Introducing the guard fixes this and allows you to handle the error if the user doesn't exist.

  • Related