Skip to content
This repository was archived by the owner on Jun 14, 2019. It is now read-only.

WIP feature replacement #38

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 32 additions & 20 deletions builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ import (
type optype byte

const (
condType optype = iota // only conditions
selectType // select
insertType // insert
updateType // update
deleteType // delete
unionType // union
condType optype = iota // only conditions
selectType // select
insertType // insert
updateType // update
deleteType // delete
unionType // union
replaceType // replace
)

const (
Expand Down Expand Up @@ -47,20 +48,21 @@ type limit struct {
// Builder describes a SQL statement
type Builder struct {
optype
dialect string
isNested bool
tableName string
subQuery *Builder
cond Cond
selects []string
joins []join
unions []union
limitation *limit
inserts Eq
updates []Eq
orderBy string
groupBy string
having string
dialect string
isNested bool
tableName string
subQuery *Builder
cond Cond
selects []string
joins []join
unions []union
limitation *limit
inserts Eq
updates []Eq
replacements []interface{}
orderBy string
groupBy string
having string
}

// Dialect sets the db dialect of Builder.
Expand Down Expand Up @@ -131,6 +133,14 @@ func (b *Builder) TableName() string {
return b.tableName
}

// Replace replace SQL
func (b *Builder) Replace(replacements ...interface{}) *Builder {
b.replacements = replacements
b.optype = replaceType

return b
}

// Into sets insert table name
func (b *Builder) Into(tableName string) *Builder {
b.tableName = tableName
Expand Down Expand Up @@ -278,6 +288,8 @@ func (b *Builder) WriteTo(w Writer) error {
return b.deleteWriteTo(w)
case unionType:
return b.unionWriteTo(w)
case replaceType:
return b.replaceWriteTo(w)
}

return ErrNotSupportType
Expand Down
80 changes: 80 additions & 0 deletions builder_replace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright 2018 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package builder

import (
"fmt"
"strings"
)

func (b *Builder) replaceWriteTo(w Writer) error {
if len(b.tableName) == 0 {
return ErrNoTableName
}

if len(b.replacements) == 0 && b.subQuery == nil {
return fmt.Errorf("empty replacements")
}

var cols []string
var conditions []Eq
if len(b.replacements) > 0 {
switch b.replacements[0].(type) {
case string:
cols = make([]string, 0, len(b.replacements))
for e := range b.replacements {
if val, ok := b.replacements[e].(string); ok {
cols = append(cols, val)
} else {
return fmt.Errorf("non-uniform types")
}
}

if b.subQuery == nil {
return fmt.Errorf("derived table should not be empty")
}
case Eq:
conditions = make([]Eq, 0, len(b.replacements))
for e := range b.replacements {
if val, ok := b.replacements[e].(Eq); ok {
conditions = append(conditions, val)
} else {
return fmt.Errorf("non-uniform types in replacements")
}
}
default:
return fmt.Errorf("unsupported replacement type, supposed to be string or Eq cond")
}
}

switch b.dialect {
case MYSQL:
if len(conditions) > 0 {
fmt.Fprintf(w, "REPLACE INTO %v SET ", b.tableName)

for e := range conditions {
if err := conditions[e].WriteTo(w); err != nil {
return err
}

if e != len(conditions)-1 {
fmt.Fprintf(w, ",")
}
}
} else {
if len(cols) == 0 {
fmt.Fprintf(w, "REPLACE INTO %v ", b.tableName)
} else {
fmt.Fprintf(w, "REPLACE INTO %v(%v) ", b.tableName, strings.Join(cols, ","))
}

return b.subQuery.WriteTo(w)
}
default:
return ErrNotSupportType
}

return nil
}
32 changes: 32 additions & 0 deletions builder_replace_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2018 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package builder

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestBuilder_Replace(t *testing.T) {
sql, err := MySQL().Replace(Eq{"a": 1}, Eq{"b": 2}, Eq{"c": "3"}).Into("table1").ToBoundSQL()
assert.NoError(t, err)
assert.EqualValues(t, "REPLACE INTO table1 SET a=1,b=2,c='3'", sql)

sql, err = MySQL().Replace().Into("table1").From(
Select("a", "b", "c").From("table2")).ToBoundSQL()
assert.NoError(t, err)
assert.EqualValues(t, "REPLACE INTO table1 SELECT a,b,c FROM table2", sql)

sql, err = MySQL().Replace("a", "b", "c").Into("table1").From(
Select("a", "b", "c").From("table2")).ToBoundSQL()
assert.NoError(t, err)
assert.EqualValues(t, "REPLACE INTO table1(a,b,c) SELECT a,b,c FROM table2", sql)

sql, err = MySQL().Replace("a", "b", "c").Into("table1").From(
Select("a", "b", "c").From("table2").Where(Neq{"a": 1})).ToBoundSQL()
assert.NoError(t, err)
assert.EqualValues(t, "REPLACE INTO table1(a,b,c) SELECT a,b,c FROM table2 WHERE a<>1", sql)
}