Home > other >  Vapor 4 Unable to Update Optional Parent with Put HTPP Request
Vapor 4 Unable to Update Optional Parent with Put HTPP Request

Time:05-19

I have a model called jurisdictions that houses political jurisdictions. Now theres jurisdictions can sit within other jurisdictions, so I have an optional parent jurisdiction...

Now I can create new jurisdictions just fine, but if I attempt to use a put request to update a jurisdictions parent, I get the following error:

FluentKit/OptionalParent.swift:20: Fatal error: OptionalParent relation OptionalParent<Jurisdiction, Jurisdiction>(key: parent_jurisdiction_id) is get-only.
2022-05-18 13:39:12.421882-0700 Run[32583:5555712] FluentKit/OptionalParent.swift:20: Fatal error: OptionalParent relation OptionalParent<Jurisdiction, Jurisdiction>(key: parent_jurisdiction_id) is get-only.```

Jurisdictions Model

import Fluent
import Vapor

final class Jurisdiction: Model, Content {
    static let schema = "jurisdictions"
    
    @ID(key: .id)
    var id: UUID?

    @OptionalParent(key: "parent_jurisdiction_id")
    var jurisdiction: Jurisdiction?
    
    @Field(key: "name")
    var name: String
    
    @Field(key: "scope")
    var scope: String
    
    @Children(for: \.$jurisdiction)
    var jurisdictions: [Jurisdiction]
    
    
    init() { }

    init(name:String, scope:String,parentJurisdictionID:UUID? = nil) {
        self.name = name
        self.scope = scope
        self.$jurisdiction.id = parentJurisdictionID
    }
}

Jurisdiction Migration

import Foundation
import Vapor
import Fluent
import FluentPostgresDriver

struct CreateJurisdiction: Migration {
    
    func prepare(on database: Database) -> EventLoopFuture<Void> {
        database.schema("jurisdictions")
            .id()
            //parent fields
        
            //attribute fields
            .field("name", .string, .required)
            .field("scope",.string, .required)
            
            //make unique on:
            .unique(on: "name", "scope")
            
            //create scheme
            .create()
    }

    func revert(on database: Database) -> EventLoopFuture<Void> {
        database.schema("jurisdictions").delete()
    }
}

struct AddParentJurisdictionToJurisdictions: Migration {
    func prepare(on database: Database) -> EventLoopFuture<Void> {
        database.schema("jurisdictions")
            .field("parent_jurisdiction_id", .uuid, .references("jurisdictions", "id"))
            .update()
    }
    func revert(on database: Database) -> EventLoopFuture<Void> {
        database.schema("jurisdictions")
            .deleteField("parent_jurisdiction_id")
            .delete()
    }
}

Jurisdiction Controller

import Foundation
import Vapor
import Fluent
import FluentPostgresDriver

struct JurisdictionsController: RouteCollection {
    func boot(routes: RoutesBuilder) throws {
        
        let jurisdictions = routes.grouped("jurisdictions")
        jurisdictions.put(use: update)

           }
        
        }
    //
    
    func update(req:Request) throws -> EventLoopFuture<HTTPStatus> {
        
        let jurisdiction = try req.content.decode(Jurisdiction.self)
        
        return  Jurisdiction.find(jurisdiction.id,on: req.db)
            .unwrap(or:Abort(.notFound))
            .flatMap {
                $0.name = jurisdiction.name
                $0.scope = jurisdiction.scope
                $0.jurisdiction = $0.jurisdiction //if I remove this line it works
                return $0.update(on: req.db).transform(to: .ok)
            }

    }
    
    

}

using a put http request looking like this: http://localhost:8080/jurisdictions with the following content produces the error...don't know what to do here.

{
    "scope": "locasl",
    "id": "0C6D5F6E-0244-4ABE-847F-2AF89CA27C30",
    "jurisdiction": {
        "id": "128133B0-25FE-4B6C-B211-CE01AA236AF9"
    },
    "name": "local"
}

CodePudding user response:

With Fluent and relations if you're trying to set properties you need to do it via the property wrapper rather than the property itself. So in your case it should be

$0.$jurisdiction.id = jurisdiction.id

This allows you to update the relation with only the parent ID rather than requiring the whole parent, in the same way as the initialiser.

  • Related