postgresqlgogo-gormgqlgen

Unsupported relations in gorm


I'm trying to Preload data from a One to Many relationship, yet I always get an "ApiKeys: unsupported relations for schema Client" error. (The reason structs are pointers is because I'm using gqlgen and that's the default configuration)

type Client struct {
    //  Client ID
    ID int `json:"id"`
    UserName string `json:"userName"`
    //  Client login hashed password
    Password string `json:"password"`
    //  ApiKeys
    APIKeys []*APIKey `json:"apiKeys"`
}
    
type APIKey struct {
    //  ApiKey Index
    ID int `json:"id"`
    //  ApiKey Value
    Key string `json:"key"`
    //  ApiKey Client Relation
    ClientID int `json:"clientID"`
    //  ApiKey Client Info
    Client *Client `json:"client"`
}

And this is the function that calls the Preload of ApiKeys.

func (r *queryResolver) ClientInfoResolver(username string, password string) (*model.Client, error) {
    var clients []*model.Client
    var client *model.Client
    query := r.Resolver.DB
    
    query = query.Where("user_name = ? AND password = ?", username, password).Preload("ApiKeys").Find(&clients)
    
    if query.Error != nil {
        return client, query.Error
    }
    return clients[0], nil
}

I understand by gorm's documentation that the foreign key for the relation is ClientID, despite not being explicit (doesn't work by specifying it either) am I understanding something wrong here?


Solution

  • You list APIKeys as the struct field name but try and use ApiKeys as the FK.

    .Preload("ApiKeys")
    // Should be
    .Preload("APIKeys")
    

    Or, if you want to use ApiKeys as the foreign key, use a Gorm struct tag to do this.

    Full working example

    package main
    
    import (
        "fmt"
        "gorm.io/driver/sqlite"
        "gorm.io/gorm"
    )
    
    type Client struct {
        //  ApiKey Index
        ID int `json:"id"`
        UserName string `json:"userName"`
        //  Client login hashed password
        Password string `json:"password"`
        //  ApiKeys
        APIKeys []*APIKey `json:"apiKeys"`
    }
    
    type APIKey struct {
        //  ApiKey Index
        ID int `json:"id"`
        //  ApiKey Value
        Key string `json:"key"`
        //  ApiKey Client Relation
        ClientID int `json:"clientID"`
        //  ApiKey Client Info
        Client *Client `json:"client"`
    }
    
    func main() {
    
        db, err := gorm.Open(sqlite.Open("many2many.db"), &gorm.Config{})
        if err != nil {
            panic("failed to connect database")
        }
    
        // Migrate the schema
        err = db.AutoMigrate(&APIKey{}, &Client{})
        if err != nil {
            fmt.Print(err)
        }
    
        clientOne := Client{
            UserName:          "Client One",
        }
        db.Create(&clientOne)
    
        apiKeyOne := APIKey{
            Key:"one",
            Client: &clientOne,
        }
        apiKeyTwo := APIKey{
            Key:"two",
            Client: &clientOne,
        }
    
        db.Create(&apiKeyOne)
        db.Create(&apiKeyTwo)
    
        // Fetch from DB
        fetchedClient := Client{}
    
        db.Debug().Preload("APIKeys").Find(&fetchedClient, clientOne.ID)
        fmt.Println(fetchedClient)
    
        db.Delete(&clientOne)
        db.Delete(&apiKeyOne)
        db.Delete(&apiKeyTwo)
    }