Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Many-to-Many relations in Vapor 3 with Fluent

Tags:

mysql

swift

vapor

I was wondering how to create many-to-many relations in Vapor 3 using Fluent and FluentMySQL as described in the Vapor 2 docs

Sadly, the docs for Vapor 3 have not been updated yet and the implementation for the Pivot protocol has changed.

Here is what I'm trying to do: I have two classes, User and Community. A Community has members and Users can be members of multiple Communitys.

Currently, my code looks like this:

import Vapor
import FluentMySQL

final class Community: MySQLModel {
    var id: Int?
    //Community Attributes here
}

final class User: MySQLModel {
    var id: Int?
    //User Attributes here
}

extension Community {
    var members: Siblings<Community, User, Pivot<Community, User>> {
        return siblings()
    }
}

However, this causes the following compiler errors:

Cannot specialize non-generic type 'Pivot' and Using 'Pivot' as a concrete type conforming to protocol 'Pivot' is not supported.

I have seen that there is a protocol extension called ModifiablePivot but I don't know how to use it since there is no documentation or sample code anywhere.

Any help is appreciated. Thanks in advance!

like image 600
larsschwegmann Avatar asked Mar 07 '23 05:03

larsschwegmann


2 Answers

Fluent 3 no longer provides a default pivot like Pivot in Fluent 2. What you should do instead is create a type that conforms to Pivot. There are some helper types in FluentMySQL for this.

final class CommunityUser: MySQLPivot {
    // implement the rest of the protocol requirements
    var communityID: Community.ID
    var userID: User.ID
}

Then use the CommunityUser in place of Pivot<Community, User>.

like image 79
tanner0101 Avatar answered Mar 15 '23 03:03

tanner0101


I had the same issue and both of the answers weren't sufficient for me, so i'm just posting my solution which worked for me.

// in CommunityUser.swift
import Vapor
import FluentMySQL


final class CommunityUser: MySQLPivot {

    typealias Left = User
    typealias Right = Community

    static var leftIDKey: LeftIDKey = \.userID
    static var rightIDKey: RightIDKey = \.communityID

    var id: Int?
    var userID: Int
    var communityID: Int

    init(id: Int?, userID: Int, communityID: Int) {
        self.id = id
        self.userID = userID
        self.communityID = communityID
    }

}

// CommunityUser didn't conform to MySQLMigration
// This simple line solves the problem
extension CommunityUser: MySQLMigration { }

For me CommunityUser also needed to be migrated in the Database.

// in configure.swift
migrations.add(model: CommunityUser.self, database: .mysql)
like image 22
Christoph P. Avatar answered Mar 15 '23 04:03

Christoph P.