sequence

This paper mainly studies OnConflict of GORM

OnConflict

Gorm. IO/[email protected] / clause/on_conflict. Go

type OnConflict struct { Columns []Column Where Where OnConstraint string DoNothing bool DoUpdates Set UpdateAll bool } func (OnConflict) Name() string { return "ON CONFLICT" } // Build build onConflict clause func (onConflict OnConflict) Build(builder Builder) { if len(onConflict.Columns) > 0 { builder.WriteByte('(') for idx, column := range onConflict.Columns { if idx > 0 { builder.WriteByte(',') } builder.WriteQuoted(column) } builder.WriteString(`) `) } if len(onConflict.Where.Exprs) > 0 { builder.WriteString("WHERE ") onConflict.Where.Build(builder) builder.WriteByte(' ') } if onConflict.OnConstraint ! = "" { builder.WriteString("ON CONSTRAINT ") builder.WriteString(onConflict.OnConstraint) builder.WriteByte(' ') } if onConflict.DoNothing { builder.WriteString("DO NOTHING") } else { builder.WriteString("DO UPDATE SET ") onConflict.DoUpdates.Build(builder) } } // MergeClause merge onConflict clauses func (onConflict OnConflict) MergeClause(clause *Clause) { clause.Expression = onConflict }Copy the code

OnConflict defines Columns, Where, OnConstraint, DoNothing, DoUpdates, UpdateAll. The Build method assembles the SQL from these properties, appending DO NOTHING if it is DoNothing and DO UPDATE SET otherwise

Expression

Gorm. IO/[email protected] / clause/set. Go

type Set []Assignment

type Assignment struct {
	Column Column
	Value  interface{}
}

func (set Set) Name() string {
	return "SET"
}

func (set Set) Build(builder Builder) {
	if len(set) > 0 {
		for idx, assignment := range set {
			if idx > 0 {
				builder.WriteByte(',')
			}
			builder.WriteQuoted(assignment.Column)
			builder.WriteByte('=')
			builder.AddVar(builder, assignment.Value)
		}
	} else {
		builder.WriteQuoted(PrimaryColumn)
		builder.WriteByte('=')
		builder.WriteQuoted(PrimaryColumn)
	}
}

// MergeClause merge assignments clauses
func (set Set) MergeClause(clause *Clause) {
	copiedAssignments := make([]Assignment, len(set))
	copy(copiedAssignments, set)
	clause.Expression = Set(copiedAssignments)
}

func Assignments(values map[string]interface{}) Set {
	keys := make([]string, 0, len(values))
	for key := range values {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	assignments := make([]Assignment, len(keys))
	for idx, key := range keys {
		assignments[idx] = Assignment{Column: Column{Name: key}, Value: values[key]}
	}
	return assignments
}

func AssignmentColumns(values []string) Set {
	assignments := make([]Assignment, len(values))
	for idx, value := range values {
		assignments[idx] = Assignment{Column: Column{Name: value}, Value: Column{Table: "excluded", Name: value}}
	}
	return assignments
}
Copy the code

The DoUpdates attribute is Set, which is actually Assignment array. The Build method assembles the ASSIGNMENT’s SQL

The instance

func onConflictDemo(db *gorm.DB) { entities := []DemoEntity{ { Model: gorm.Model{ID: 1}, Name: "coco", }, { Model: gorm.Model{ID: 2}, Name: "bear", }, } result := db.Debug().Create(&entities) b, _ := json.Marshal(entities) log.Println("data:", string(b)) log.Println("result.RowsAffected:", result.RowsAffected, "result.Error:", result.Error) if err := db.Debug().Clauses(clause.OnConflict{DoNothing: true}).Create(&entities).Error; err ! = nil { panic(err) } }Copy the code

The output

2021/01/17 20:03:31 /demo.go:53 UNIQUE constraint failed: Id [rows:0] INSERT INTO 'entities' (' created_at', 'updated_at', 'deleted_at', 'name', 'id') VALUES (" 2021-01-17 20:03:31. 711 ", "the 2021-01-17 20:03:31. 711", NULL, "coco", 1), (" the 2021-01-17 20:03:31. 711 ", "2021-01-17 20:03:31. 711 ", NULL, "bear", 2) 2021/01/17 20:03:31 data: [{" ID ": 1," CreatedAt ":" the 2021-01-17 T20:03:31. 71143 + 08:00 ", "UpdatedAt" : "the 2021-01-17 T20:03:31. 71143 + 08:00", "DeletedAt:" null, "N Ame ":" coco "}, {" ID ": 2," CreatedAt ":" the 2021-01-17 T20:03:31. 71143 + 08:00 ", "UpdatedAt" : "the 2021-01-17 T20:03:31. 71143 + 08:00", "Delete dAt":null,"Name":"bear"}] 2021/01/17 20:03:31 result.RowsAffected: 0 result.Error: UNIQUE constraint failed: Id 2021/01/17 20:03:31 /demo.go:58 [rows:0] INSERT INTO 'demo_entities' (` created_at `, ` updated_at `, ` deleted_at `, ` name `, ` id `) VALUES (" 2021-01-17 20:03:31. 711 ", "2021-01-17 20:03:31.711",NULL,"coco",1),("2021-01-17 20:03:31.711","2021-01-17 20:03:31.711",NULL,"bear",2) ON CONFLICT DO NOTHINGCopy the code

summary

Gorm OnConflict defines Columns, Where, OnConstraint, DoNothing, DoUpdates, and UpdateAll. The Build method assembles the SQL from these properties, appending DO NOTHING if it is DoNothing and DO UPDATE SET otherwise.

doc

  • gorm