diff --git a/integrations/session_upsert_test.go b/integrations/session_upsert_test.go index 6ae46cc0..9970d3d8 100644 --- a/integrations/session_upsert_test.go +++ b/integrations/session_upsert_test.go @@ -461,7 +461,7 @@ func TestUpsert(t *testing.T) { assert.Equal(t, int64(1), n) // Update default - n, err = testEngine.Upsert(&NoAutoIncrementPrimaryKey{NotUnique: "notunique"}) + n, err = testEngine.Upsert([]*NoAutoIncrementPrimaryKey{{NotUnique: "notunique"}}) assert.NoError(t, err) assert.Equal(t, int64(1), n) @@ -471,7 +471,7 @@ func TestUpsert(t *testing.T) { assert.Equal(t, int64(1), n) // Insert with 2 - n, err = testEngine.Upsert(&NoAutoIncrementPrimaryKey{Name: "two", Number: 2}) + n, err = testEngine.Upsert([]*NoAutoIncrementPrimaryKey{{Name: "two", Number: 2}}) assert.NoError(t, err) assert.Equal(t, int64(1), n) @@ -479,5 +479,154 @@ func TestUpsert(t *testing.T) { n, err = testEngine.Upsert(&NoAutoIncrementPrimaryKey{Name: "one", Number: 1, NotUnique: "updated"}) assert.NoError(t, err) assert.Equal(t, int64(1), n) + + // Upsert multiple with 2 + n, err = testEngine.Upsert([]*NoAutoIncrementPrimaryKey{{Name: "one", Number: 1, NotUnique: "updatedagain"}, {Name: "three", Number: 3}}) + assert.NoError(t, err) + assert.Equal(t, int64(2), n) }) } + +func TestInsertOnConflictDoNothingMap(t *testing.T) { + type MultiUniqueMap struct { + ID int64 `xorm:"pk autoincr"` + NotUnique string + Data1 string `xorm:"UNIQUE(s) NOT NULL"` + Data2 string `xorm:"UNIQUE(s) NOT NULL"` + } + + assert.NoError(t, testEngine.Sync2(&MultiUniqueMap{})) + _, _ = testEngine.Exec("DELETE FROM multi_unique_map") + + n, err := testEngine.Table(&MultiUniqueMap{}).InsertOnConflictDoNothing(map[string]interface{}{ + "not_unique": "", + "data1": "", + "data2": "", + }) + assert.NoError(t, err) + assert.Equal(t, int64(1), n) + + n, err = testEngine.Table(&MultiUniqueMap{}).InsertOnConflictDoNothing(map[string]interface{}{ + "not_unique": "", + "data1": "second", + "data2": "", + }) + assert.NoError(t, err) + assert.Equal(t, int64(1), n) + + n, err = testEngine.Table(&MultiUniqueMap{}).InsertOnConflictDoNothing(map[string]interface{}{ + "not_unique": "", + "data1": "", + "data2": "", + }) + assert.NoError(t, err) + assert.Equal(t, int64(0), n) + + n, err = testEngine.Table(&MultiUniqueMap{}).InsertOnConflictDoNothing(map[string]interface{}{ + "not_unique": "", + "data1": "", + "data2": "third", + }) + assert.NoError(t, err) + assert.Equal(t, int64(1), n) + + n, err = testEngine.Table(&MultiUniqueMap{}).InsertOnConflictDoNothing(map[string]interface{}{ + "not_unique": "", + "data1": "", + "data2": "third", + }) + assert.NoError(t, err) + assert.Equal(t, int64(0), n) +} + +func TestUpsertMap(t *testing.T) { + type MultiUniqueMap struct { + ID int64 `xorm:"pk autoincr"` + NotUnique string + Data1 string `xorm:"UNIQUE(s) NOT NULL"` + Data2 string `xorm:"UNIQUE(s) NOT NULL"` + } + + assert.NoError(t, testEngine.Sync2(&MultiUniqueMap{})) + _, _ = testEngine.Exec("DELETE FROM multi_unique_map") + + n, err := testEngine.Table(&MultiUniqueMap{}).Upsert(map[string]interface{}{ + "not_unique": "", + "data1": "", + "data2": "", + }) + assert.NoError(t, err) + assert.Equal(t, int64(1), n) + + testCase := &MultiUniqueMap{} + has, err := testEngine.Get(testCase) + assert.NoError(t, err) + assert.True(t, has) + + n, err = testEngine.Table(&MultiUniqueMap{}).Upsert(map[string]interface{}{ + "not_unique": "", + "data1": "second", + "data2": "", + }) + assert.NoError(t, err) + assert.Equal(t, int64(1), n) + testCase = &MultiUniqueMap{ + Data1: "second", + } + has, err = testEngine.Get(testCase) + assert.NoError(t, err) + assert.True(t, has) + + n, err = testEngine.Table(&MultiUniqueMap{}).Upsert(map[string]interface{}{ + "not_unique": "updated", + "data1": "", + "data2": "", + }) + assert.NoError(t, err) + assert.Equal(t, int64(1), n) + testCase = &MultiUniqueMap{ + Data1: "", + } + has, err = testEngine.Get(testCase) + assert.NoError(t, err) + assert.True(t, has) + assert.Equal(t, "updated", testCase.NotUnique) + + n, err = testEngine.Table(&MultiUniqueMap{}).Upsert(map[string]interface{}{ + "not_unique": "", + "data1": "", + "data2": "third", + }) + assert.NoError(t, err) + assert.Equal(t, int64(1), n) + testCase = &MultiUniqueMap{ + Data2: "third", + } + has, err = testEngine.Get(testCase) + assert.NoError(t, err) + assert.True(t, has) + assert.Equal(t, "", testCase.NotUnique) + + n, err = testEngine.Table(&MultiUniqueMap{}).Upsert(map[string]interface{}{ + "not_unique": "updated", + "data1": "", + "data2": "third", + }) + assert.NoError(t, err) + assert.Equal(t, int64(1), n) + testCase = &MultiUniqueMap{ + Data2: "third", + } + has, err = testEngine.Get(testCase) + assert.NoError(t, err) + assert.True(t, has) + assert.Equal(t, "updated", testCase.NotUnique) + + testCase = &MultiUniqueMap{ + Data1: "second", + } + has, err = testEngine.Get(testCase) + assert.NoError(t, err) + assert.True(t, has) + assert.Equal(t, "", testCase.NotUnique) +} diff --git a/internal/statements/upsert.go b/internal/statements/upsert.go index 098a11fb..218ce758 100644 --- a/internal/statements/upsert.go +++ b/internal/statements/upsert.go @@ -98,12 +98,14 @@ func (statement *Statement) GenUpsertSQL(doUpdate bool, addOuput bool, columns [ return "", nil, fmt.Errorf("unimplemented") // FIXME: UPSERT } - if len(table.AutoIncrement) > 0 && - (statement.dialect.URI().DBType == schemas.POSTGRES || - statement.dialect.URI().DBType == schemas.SQLITE) { - write(" RETURNING ") - if err := statement.dialect.Quoter().QuoteTo(buf.Builder, table.AutoIncrement); err != nil { - return "", nil, err + if addOuput { + if len(table.AutoIncrement) > 0 && + (statement.dialect.URI().DBType == schemas.POSTGRES || + statement.dialect.URI().DBType == schemas.SQLITE) { + write(" RETURNING ") + if err := statement.dialect.Quoter().QuoteTo(buf.Builder, table.AutoIncrement); err != nil { + return "", nil, err + } } } diff --git a/session_upsert.go b/session_upsert.go index f4b896dc..d37f0b3b 100644 --- a/session_upsert.go +++ b/session_upsert.go @@ -31,6 +31,8 @@ func (session *Session) upsert(doUpdate bool, beans ...interface{}) (int64, erro session.autoResetStatement = true session.resetStatement() }() + + fmt.Println(session.statement.TableName()) for _, bean := range beans { var cnt int64 var err error @@ -116,6 +118,9 @@ func (session *Session) upsertMap(doUpdate bool, columns []string, args []interf if len(tableName) == 0 { return 0, ErrTableNotFound } + if session.statement.RefTable == nil { + return 0, ErrTableNotFound + } uniqueColValMap, uniqueConstraints, err := session.getUniqueColumns(doUpdate, columns, args) if err != nil {