Search code examples
gogo-gorm

golang gorm upsert with returning


In my golang project I use gorm and I need to make upsert query with returning clause to get the modified value from the query. I can make upsert, but I cannot figure out how to connect the returnning clause to it. The table name is counters, the code is as follows:

te := struct {
        Name string //key column
        Counter int
    }{
        Name: "name_to_update",
        Counter: 2,
    }

DB.
    //Model(te).
    Clauses(
        //clause.Returning{Columns: []clause.Column{{Name: "counter"}}},
        clause.OnConflict{
            Columns: []clause.Column{{Name: "name"}}, // key column
            DoUpdates: clause.Assignments(map[string]interface{}{
                "counter": gorm.Expr("counters.counter + ?", 1),
            }),
        },
    ).Create(&te)

The resulting SQL query is:

INSERT INTO "counters" ("counter", "name") VALUES (0, "name_to_update") ON CONFLICT ("name") 
DO UPDATE SET "counter"=counters.counter + 1 RETURNING "name" //I need updated counter value here, not name  

So the counter is updated and this is OK, but it returns me the key column (in RETURNING) while I need the updated value of the counter. Any ideas how to fix it? Thank you


Solution

  • I'm not sure if the anonymous struct causes an issue.

    Also, it's unclear from your code where the table name - "counters" - comes from.

    I've tried your solution - but with a dedicated struct for the model - and it works just fine.

    type Counter struct {
        Name    string `gorm:"primaryKey"`
        Counter int
    }
    
    ...
    
    counter := Counter{Name: "name_to_update", Counter: 2}
    
        db.
            Clauses(
                clause.Returning{Columns: []clause.Column{{Name: "counter"}}},
                clause.OnConflict{
                    Columns: []clause.Column{{Name: "name"}},
                    DoUpdates: clause.Assignments(map[string]interface{}{
                        "counter": gorm.Expr("counters.counter + ?", 1),
                    }),
                },
            ).Create(&counter)
    
        fmt.Println(counter.Counter)
    

    The code above generates the following SQL

    INSERT INTO "counters" ("name","counter") VALUES ('name_to_update',10) ON CONFLICT ("name") DO UPDATE SET "counter"=counters.counter + 1 RETURNING "counter" 
    

    And counter.Counter has correct updated value.