Search code examples
swiftvaporserver-side-swift

Vapor 2, One to Many relation


Do you have any example of how to create One to Many relation using Vapor 2? There are some examples of how to do this, but they use the old version of Vapor.

Thank you for all suggestions.


Solution

  • I have found a solution. Here is simple example of an owner having many cars, maybe will be helpful for someone.

    Owner:

    final class Owner: Model {
        static let idKey = "id"
        static let nameKey = "name"
        static let carsKey = "cars"
    
        var name: String
        let storage = Storage()
    
        var cars: Children<Owner, Car> {
            return children()
        }
    
    
        init(name: String) {
            self.name = name
        }
    
        init(row: Row) throws {
            name = try row.get(Owner.nameKey)
        }
    
        func makeRow() throws -> Row {
            var row = Row()
            try row.set(Owner.nameKey, name)
            return row
        }
    }
    
    extension Owner: Preparation {
    
        static func prepare(_ database: Database) throws {
            try database.create(self) { builder in
                builder.id()
                builder.string(Owner.nameKey)
            }
        }
    
        static func revert(_ database: Database) throws {
            try database.delete(self)
        }
    }
    
    extension Owner: JSONConvertible {
    
        convenience init(json: JSON) throws {
            try self.init(
                name: json.get(Owner.nameKey)
            )
        }
    
        func makeJSON() throws -> JSON {
            var json = JSON()
            try json.set(Owner.idKey, id)
            try json.set(Owner.nameKey, name)
            try json.set(Owner.carsKey, try cars.all())
            return json
        }
    }
    
    extension Owner: ResponseRepresentable { }
    
    extension Owner: Updateable {
        public static var updateableKeys: [UpdateableKey<Owner>] {
            return [
                UpdateableKey(Owner.nameKey, String.self) { owner, text in
                    owner.name = name
                }
            ]
        }
    }
    

    Car:

    final class Car: Model {
        static let idKey = "id"
        static let makeKey = "make"
        static let modelKey = "model"
        static let ownerIdKey = "owner_id"
    
        var make: String
        var model: String
        var ownerId: Identifier
        let storage = Storage()
    
        var owner: Parent<Car, Owner> {
            return parent(id: ownerId)
        }
    
        init(make: String, model: String, ownerId: Identifier) {
            self.make = make
            self.model = model
            self.ownerId = ownerId
        }
    
        init(row: Row) throws {
            make = try row.get(Car.makeKey)
            model = try row.get(Car.modelKey)
            ownerId = try row.get(Car.ownerIdKey)
        }
    
        func makeRow() throws -> Row {
            var row = Row()
            try row.set(Car.makeKey, make)
            try row.set(Car.modelKey, model)
            try row.set(Car.ownerIdKey, ownerId)
            return row
        }
    }
    
    extension Car: JSONConvertible {
    
        convenience init(json: JSON) throws {
            try self.init(
                make: json.get(Car.makeKey),
                model: json.get(Car.modelKey),
                ownerId: json.get(Car.ownerIdKey)
            )
        }
    
        func makeJSON() throws -> JSON {
            var json = JSON()
            try json.set(Car.idKey, id)
            try json.set(Car.makeKey, make)
            try json.set(Car.modelKey, model)
            try json.set(Car.ownerIdKey, ownerId)
            return json
        }
    }
    
    extension Car: ResponseRepresentable {}
    
    extension Car: Preparation {
    
        static func prepare(_ database: Database) throws {
            try database.create(self) { builder in
                builder.id()
                builder.string(Car.makeKey)
                builder.string(Car.modelKey)
                builder.foreignId(for: Owner.self)
            }
        }
    
        static func revert(_ database: Database) throws {
            try database.delete(self)
        }
    }
    
    extension Car: Updateable {
        public static var updateableKeys: [UpdateableKey<Car>] {
            return [
                UpdateableKey(Car.makeKey, String.self) { car, make in
                    car.make = make
                }
            ]
        }
    }