Skip to content

Commit

Permalink
fix #6. fix incorrect marker when nesting builders with PostgreSQL fl…
Browse files Browse the repository at this point in the history
…avor.
  • Loading branch information
huandu committed Feb 4, 2018
1 parent 4414789 commit 6c82d03
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 22 deletions.
11 changes: 6 additions & 5 deletions args.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,17 +71,18 @@ func (args *Args) add(arg interface{}) int {
// $0 $1 ... $n refers nth-argument passed in the call. Next $? will use arguments n+1.
// ${name} refers a named argument created by `Named` with `name`.
// $$ is a "$" string.
func (args *Args) Compile(format string) (query string, values []interface{}) {
return args.CompileWithFlavor(format, args.Flavor)
func (args *Args) Compile(format string, intialValue ...interface{}) (query string, values []interface{}) {
return args.CompileWithFlavor(format, args.Flavor, intialValue...)
}

// CompileWithFlavor compiles builder's format to standard sql with flavor and returns associated args.
//
// See doc for `Compile` to learn details.
func (args *Args) CompileWithFlavor(format string, flavor Flavor) (query string, values []interface{}) {
func (args *Args) CompileWithFlavor(format string, flavor Flavor, intialValue ...interface{}) (query string, values []interface{}) {
buf := &bytes.Buffer{}
idx := strings.IndexRune(format, '$')
offset := 0
values = intialValue

if flavor == invalidFlavor {
flavor = DefaultFlavor
Expand Down Expand Up @@ -190,9 +191,9 @@ func (args *Args) compileSuccessive(buf *bytes.Buffer, flavor Flavor, format str
func (args *Args) compileArg(buf *bytes.Buffer, flavor Flavor, values []interface{}, arg interface{}) []interface{} {
switch a := arg.(type) {
case Builder:
s, nestedArgs := a.BuildWithFlavor(flavor)
var s string
s, values = a.BuildWithFlavor(flavor, values...)
buf.WriteString(s)
values = append(values, nestedArgs...)
case sql.NamedArg:
buf.WriteRune('@')
buf.WriteString(a.Name)
Expand Down
10 changes: 5 additions & 5 deletions builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
// `SELECT * FROM t1 WHERE id IN (SELECT id FROM t2)`.
type Builder interface {
Build() (sql string, args []interface{})
BuildWithFlavor(flavor Flavor) (sql string, args []interface{})
BuildWithFlavor(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{})
}

type compiledBuilder struct {
Expand All @@ -24,8 +24,8 @@ func (cb *compiledBuilder) Build() (sql string, args []interface{}) {
return cb.args.Compile(cb.format)
}

func (cb *compiledBuilder) BuildWithFlavor(flavor Flavor) (sql string, args []interface{}) {
return cb.args.CompileWithFlavor(cb.format, flavor)
func (cb *compiledBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) {
return cb.args.CompileWithFlavor(cb.format, flavor, initialArg...)
}

type flavoredBuilder struct {
Expand All @@ -37,8 +37,8 @@ func (fb *flavoredBuilder) Build() (sql string, args []interface{}) {
return fb.builder.BuildWithFlavor(fb.flavor)
}

func (fb *flavoredBuilder) BuildWithFlavor(flavor Flavor) (sql string, args []interface{}) {
return fb.builder.BuildWithFlavor(flavor)
func (fb *flavoredBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) {
return fb.builder.BuildWithFlavor(flavor, initialArg...)
}

// WithFlavor creates a new Builder based on builder with a default flavor.
Expand Down
45 changes: 45 additions & 0 deletions builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package sqlbuilder
import (
"database/sql"
"fmt"
"reflect"
"testing"
)

func ExampleBuildf() {
Expand Down Expand Up @@ -62,7 +64,50 @@ func ExampleWithFlavor() {
fmt.Println(sql)
fmt.Println(args)

// Explicitly use MySQL as the flavor.
sql, args = WithFlavor(Buildf("SELECT * FROM foo WHERE id = %v", 1234), PostgreSQL).BuildWithFlavor(MySQL)

fmt.Println(sql)
fmt.Println(args)

// Output:
// SELECT * FROM foo WHERE id = $1
// [1234]
// SELECT * FROM foo WHERE id = ?
// [1234]
}

func TestBuildWithPostgreSQL(t *testing.T) {
sb1 := PostgreSQL.NewSelectBuilder()
sb1.Select("col1", "col2").From("t1").Where(sb1.E("id", 1234), sb1.G("level", 2))

sb2 := PostgreSQL.NewSelectBuilder()
sb2.Select("col3", "col4").From("t2").Where(sb2.E("id", 4567), sb2.LE("level", 5))

// Use DefaultFlavor (MySQL) instead of PostgreSQL.
sql, args := Build("SELECT $1 AS col5 LEFT JOIN $0 LEFT JOIN $2", sb1, 7890, sb2).Build()

if expected := "SELECT ? AS col5 LEFT JOIN SELECT col1, col2 FROM t1 WHERE id = ? AND level > ? LEFT JOIN SELECT col3, col4 FROM t2 WHERE id = ? AND level <= ?"; sql != expected {
t.Fatalf("invalid sql. [expected:%v] [actual:%v]", expected, sql)
}

if expected := []interface{}{7890, 1234, 2, 4567, 5}; !reflect.DeepEqual(args, expected) {
t.Fatalf("invalid args. [expected:%v] [actual:%v]", expected, args)
}

old := DefaultFlavor
DefaultFlavor = PostgreSQL
defer func() {
DefaultFlavor = old
}()

sql, args = Build("SELECT $1 AS col5 LEFT JOIN $0 LEFT JOIN $2", sb1, 7890, sb2).Build()

if expected := "SELECT $1 AS col5 LEFT JOIN SELECT col1, col2 FROM t1 WHERE id = $2 AND level > $3 LEFT JOIN SELECT col3, col4 FROM t2 WHERE id = $4 AND level <= $5"; sql != expected {
t.Fatalf("invalid sql. [expected:%v] [actual:%v]", expected, sql)
}

if expected := []interface{}{7890, 1234, 2, 4567, 5}; !reflect.DeepEqual(args, expected) {
t.Fatalf("invalid args. [expected:%v] [actual:%v]", expected, args)
}
}
6 changes: 3 additions & 3 deletions delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ func (db *DeleteBuilder) Build() (sql string, args []interface{}) {
return db.BuildWithFlavor(db.args.Flavor)
}

// BuildWithFlavor returns compiled DELETE string and args with flavor.
// BuildWithFlavor returns compiled DELETE string and args with flavor and initial args.
// They can be used in `DB#Query` of package `database/sql` directly.
func (db *DeleteBuilder) BuildWithFlavor(flavor Flavor) (sql string, args []interface{}) {
func (db *DeleteBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) {
buf := &bytes.Buffer{}
buf.WriteString("DELETE FROM ")
buf.WriteString(db.table)
Expand All @@ -69,7 +69,7 @@ func (db *DeleteBuilder) BuildWithFlavor(flavor Flavor) (sql string, args []inte
buf.WriteString(strings.Join(db.whereExprs, " AND "))
}

return db.args.CompileWithFlavor(buf.String(), flavor)
return db.args.CompileWithFlavor(buf.String(), flavor, initialArg...)
}

// SetFlavor sets the flavor of compiled sql.
Expand Down
6 changes: 3 additions & 3 deletions insert.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ func (ib *InsertBuilder) Build() (sql string, args []interface{}) {
return ib.BuildWithFlavor(ib.args.Flavor)
}

// BuildWithFlavor returns compiled INSERT string and args.
// BuildWithFlavor returns compiled INSERT string and args with flavor and initial args.
// They can be used in `DB#Query` of package `database/sql` directly.
func (ib *InsertBuilder) BuildWithFlavor(flavor Flavor) (sql string, args []interface{}) {
func (ib *InsertBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) {
buf := &bytes.Buffer{}
buf.WriteString("INSERT INTO ")
buf.WriteString(ib.table)
Expand All @@ -87,7 +87,7 @@ func (ib *InsertBuilder) BuildWithFlavor(flavor Flavor) (sql string, args []inte
}

buf.WriteString(strings.Join(values, ", "))
return ib.args.CompileWithFlavor(buf.String(), flavor)
return ib.args.CompileWithFlavor(buf.String(), flavor, initialArg...)
}

// SetFlavor sets the flavor of compiled sql.
Expand Down
6 changes: 3 additions & 3 deletions select.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ func (sb *SelectBuilder) Build() (sql string, args []interface{}) {
return sb.BuildWithFlavor(sb.args.Flavor)
}

// BuildWithFlavor returns compiled SELECT string and args.
// BuildWithFlavor returns compiled SELECT string and args with flavor and initial args.
// They can be used in `DB#Query` of package `database/sql` directly.
func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor) (sql string, args []interface{}) {
func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) {
buf := &bytes.Buffer{}
buf.WriteString("SELECT ")

Expand Down Expand Up @@ -183,7 +183,7 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor) (sql string, args []inte
}
}

return sb.Args.CompileWithFlavor(buf.String(), flavor)
return sb.Args.CompileWithFlavor(buf.String(), flavor, initialArg...)
}

// SetFlavor sets the flavor of compiled sql.
Expand Down
6 changes: 3 additions & 3 deletions update.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ func (ub *UpdateBuilder) Build() (sql string, args []interface{}) {
return ub.BuildWithFlavor(ub.args.Flavor)
}

// BuildWithFlavor returns compiled UPDATE string and args.
// BuildWithFlavor returns compiled UPDATE string and args with flavor and initial args.
// They can be used in `DB#Query` of package `database/sql` directly.
func (ub *UpdateBuilder) BuildWithFlavor(flavor Flavor) (sql string, args []interface{}) {
func (ub *UpdateBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) {
buf := &bytes.Buffer{}
buf.WriteString("UPDATE ")
buf.WriteString(ub.table)
Expand All @@ -120,7 +120,7 @@ func (ub *UpdateBuilder) BuildWithFlavor(flavor Flavor) (sql string, args []inte
buf.WriteString(strings.Join(ub.whereExprs, " AND "))
}

return ub.args.CompileWithFlavor(buf.String(), flavor)
return ub.args.CompileWithFlavor(buf.String(), flavor, initialArg...)
}

// SetFlavor sets the flavor of compiled sql.
Expand Down

0 comments on commit 6c82d03

Please sign in to comment.