diff --git a/CHANGELOG.md b/CHANGELOG.md index 29f27a9..c8b10e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,11 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - added `BitBool` for mysql bit type (#11) - added `sharding` feature (#12) -- added `On` on `DB` to enable AutoSharding feature(#13) -- added `On` on `SQLBuilder` to enable AutoRotation feature(#13) +- added `On` on `DB` to enable AutoSharding feature (#13) +- added `On` on `SQLBuilder` to enable AutoRotation feature (#13) ### Fixed -- fixed parameterized placeholder for postgresql(#12) +- fixed parameterized placeholder for postgresql (#12) +- sorted columns in `SetMap` for PrepareStmt performance (#14) ## [1.1.0] - 2024-02-13 ### Added diff --git a/sqlbuilder.go b/sqlbuilder.go index 4263bd7..b4049db 100644 --- a/sqlbuilder.go +++ b/sqlbuilder.go @@ -2,6 +2,7 @@ package sqle import ( "errors" + "sort" "strings" "github.com/yaitoo/sqle/shardid" @@ -178,6 +179,40 @@ func (b *Builder) Delete(table string) *Builder { return b } +func (b *Builder) sortColumns(m map[string]any, opts ...BuilderOption) []string { + + bo := &BuilderOptions{} + for _, opt := range opts { + opt(bo) + } + + hasCustomizedColumns := len(bo.Columns) > 0 + + for n, v := range m { + + name := n + + if bo.ToName != nil { + name = bo.ToName(name) + if name != n { + m[name] = v + } + + } + + if !hasCustomizedColumns { + bo.Columns = append(bo.Columns, name) + } + } + + if !hasCustomizedColumns { + sort.Strings(bo.Columns) + } + + return bo.Columns + +} + func (b *Builder) On(id shardid.ID) *Builder { rn := id.RotateName() if rn != "" { diff --git a/sqlbuilder_insert.go b/sqlbuilder_insert.go index a5ccbac..0818da6 100644 --- a/sqlbuilder_insert.go +++ b/sqlbuilder_insert.go @@ -61,22 +61,9 @@ func (ib *InsertBuilder) SetMap(m map[string]any, opts ...BuilderOption) *Insert return ib } - bo := &BuilderOptions{} - for _, opt := range opts { - opt(bo) - } - - for n, v := range m { - if bo.ToName != nil { - sn := bo.ToName(n) - if sn != n { - delete(m, n) - m[sn] = v - } - } - } + columns := ib.b.sortColumns(m, opts...) - for _, n := range bo.Columns { + for _, n := range columns { v, ok := m[n] if ok { ib.Set(n, v) diff --git a/sqlbuilder_test.go b/sqlbuilder_test.go index 609e95f..bc8fd45 100644 --- a/sqlbuilder_test.go +++ b/sqlbuilder_test.go @@ -528,6 +528,50 @@ func TestBuilder(t *testing.T) { }, }, + { + name: "build_with_map_should_be_sorted", + build: func() *Builder { + m := make(map[string]any) + + m["user_id"] = "x1234" + m["id"] = 1 + + b := New().Insert("users").SetMap(m).End() + + return b + }, + assert: func(t *testing.T, b *Builder) { + s, vars, err := b.Build() + require.NoError(t, err) + require.Equal(t, "INSERT INTO `users` (`id`, `user_id`) VALUES (?, ?)", s) + require.Len(t, vars, 2) + require.Equal(t, 1, vars[0]) + require.Equal(t, "x1234", vars[1]) + + }, + }, + { + name: "build_with_map_and_allow_should_not_be_sorted", + build: func() *Builder { + m := make(map[string]any) + + m["user_id"] = "x1234" + m["id"] = 1 + + b := New().Insert("users").SetMap(m, WithAllow("user_id", "id")).End() + + return b + }, + assert: func(t *testing.T, b *Builder) { + s, vars, err := b.Build() + require.NoError(t, err) + require.Equal(t, "INSERT INTO `users` (`user_id`, `id`) VALUES (?, ?)", s) + require.Len(t, vars, 2) + require.Equal(t, "x1234", vars[0]) + require.Equal(t, 1, vars[1]) + + }, + }, } for _, test := range tests { diff --git a/sqlbuilder_update.go b/sqlbuilder_update.go index 194300f..0ea9714 100644 --- a/sqlbuilder_update.go +++ b/sqlbuilder_update.go @@ -1,6 +1,8 @@ package sqle -import "reflect" +import ( + "reflect" +) type UpdateBuilder struct { *Builder @@ -42,22 +44,9 @@ func (ub *UpdateBuilder) SetMap(m map[string]any, opts ...BuilderOption) *Update return ub } - bo := &BuilderOptions{} - for _, opt := range opts { - opt(bo) - } - - for n, v := range m { - if bo.ToName != nil { - sn := bo.ToName(n) - if sn != n { - delete(m, n) - m[sn] = v - } - } - } + columns := ub.sortColumns(m, opts...) - for _, n := range bo.Columns { + for _, n := range columns { v, ok := m[n] if ok { ub.Set(n, v)