Finish Insert() caching.

This commit is contained in:
Aaron L 2016-09-03 12:47:27 -07:00
parent 793306d749
commit acad9f7de5
7 changed files with 65 additions and 39 deletions

View file

@ -237,12 +237,12 @@ func bind(rows *sql.Rows, obj interface{}, structType, sliceType reflect.Type, b
switch bkind {
case kindStruct:
pointers = ptrsFromMapping(reflect.Indirect(reflect.ValueOf(obj)), mapping)
pointers = PtrsFromMapping(reflect.Indirect(reflect.ValueOf(obj)), mapping)
case kindSliceStruct:
pointers = ptrsFromMapping(oneStruct, mapping)
pointers = PtrsFromMapping(oneStruct, mapping)
case kindPtrSliceStruct:
newStruct = reflect.New(structType)
pointers = ptrsFromMapping(reflect.Indirect(newStruct), mapping)
pointers = PtrsFromMapping(reflect.Indirect(newStruct), mapping)
}
if err != nil {
return err
@ -295,19 +295,29 @@ ColLoop:
return ptrs, nil
}
// ptrsFromMapping expects to be passed an addressable struct that it's looking
// for things on.
func ptrsFromMapping(val reflect.Value, mapping []uint64) []interface{} {
// PtrsFromMapping expects to be passed an addressable struct and a mapping
// of where to find things. It pulls the pointers out referred to by the mapping.
func PtrsFromMapping(val reflect.Value, mapping []uint64) []interface{} {
ptrs := make([]interface{}, len(mapping))
for i, m := range mapping {
ptrs[i] = ptrFromMapping(val, m).Interface()
ptrs[i] = ptrFromMapping(val, m, true).Interface()
}
return ptrs
}
// ValuesFromMapping expects to be passed an addressable struct and a mapping
// of where to find things. It pulls the pointers out referred to by the mapping.
func ValuesFromMapping(val reflect.Value, mapping []uint64) []interface{} {
ptrs := make([]interface{}, len(mapping))
for i, m := range mapping {
ptrs[i] = ptrFromMapping(val, m, false).Interface()
}
return ptrs
}
// ptrFromMapping expects to be passed an addressable struct that it's looking
// for things on.
func ptrFromMapping(val reflect.Value, mapping uint64) reflect.Value {
func ptrFromMapping(val reflect.Value, mapping uint64, addressOf bool) reflect.Value {
for i := 0; i < 8; i++ {
v := (mapping >> uint(i*8)) & sentinel

View file

@ -247,19 +247,19 @@ func TestPtrFromMapping(t *testing.T) {
},
}
v := ptrFromMapping(reflect.Indirect(reflect.ValueOf(val)), testMakeMapping(0))
v := ptrFromMapping(reflect.Indirect(reflect.ValueOf(val)), testMakeMapping(0), true)
if got := *v.Interface().(*int); got != 5 {
t.Error("flat int was wrong:", got)
}
v = ptrFromMapping(reflect.Indirect(reflect.ValueOf(val)), testMakeMapping(1))
v = ptrFromMapping(reflect.Indirect(reflect.ValueOf(val)), testMakeMapping(1), true)
if got := *v.Interface().(*int); got != 0 {
t.Error("flat pointer was wrong:", got)
}
v = ptrFromMapping(reflect.Indirect(reflect.ValueOf(val)), testMakeMapping(2, 0))
v = ptrFromMapping(reflect.Indirect(reflect.ValueOf(val)), testMakeMapping(2, 0), true)
if got := *v.Interface().(*int); got != 6 {
t.Error("nested int was wrong:", got)
}
v = ptrFromMapping(reflect.Indirect(reflect.ValueOf(val)), testMakeMapping(2, 1))
v = ptrFromMapping(reflect.Indirect(reflect.ValueOf(val)), testMakeMapping(2, 1), true)
if got := *v.Interface().(*int); got != 0 {
t.Error("nested pointer was wrong:", got)
}

View file

@ -146,6 +146,8 @@ var defaultTemplateImports = imports{
`"fmt"`,
`"strings"`,
`"database/sql"`,
`"reflect"`,
`"sync"`,
`"time"`,
},
thirdParty: importList{
@ -166,6 +168,7 @@ var defaultSingletonTemplateImports = map[string]imports{
"boil_types": {
thirdParty: importList{
`"github.com/pkg/errors"`,
`"github.com/vattle/sqlboiler/strmangle"`,
},
},
}

View file

@ -1,3 +1,5 @@
{{if .Table.IsJoinTable -}}
{{else -}}
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
{{- $tableNameSingular := .Table.Name | singular | titleCase -}}
var (
@ -20,26 +22,14 @@ type (
// Cache for insert and update
var (
{{$varNameSingular}}Mapping = boil.MakeStructMapping(&{{$tableNameSingular}}{})
{{$varNameSingular}}InsertCacheMut sync.RMutex
{{$varNameSingular}}Type = reflect.TypeOf(&{{$tableNameSingular}}{})
{{$varNameSingular}}Mapping = boil.MakeStructMapping({{$varNameSingular}}Type)
{{$varNameSingular}}InsertCacheMut sync.RWMutex
{{$varNameSingular}}InsertCache = make(map[string]insertCache)
{{$varNameSingular}}UpdateCacheMut sync.RMutex
{{$varNameSingular}}UpdateCacheMut sync.RWMutex
{{$varNameSingular}}UpdateCache = make(map[string]updateCache)
)
func makeCacheKey(wl, nzDefaults []string) string {
buf := strmangle.GetBuffer()
for _, w := range wl {
buf.WriteString(w)
}
for _, nz := range nzDefaults {
buf.WriteString(nz)
}
str := buf.String()
strmangle.PutBuffer(buf)
}
// Force time package dependency for automated UpdatedAt/CreatedAt.
var _ = time.Second
{{end -}}

View file

@ -56,20 +56,26 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
whitelist,
)
typ := reflect.TypeOf(o)
cache.valueMapping = boil.BindMapping(typ, {{$varNameSingular}}Mapping, wl)
cache.retMapping = boil.BindMapping(typ, {{$varNameSingular}}Mapping, returnColumns)
cache.valueMapping, err = boil.BindMapping({{$varNameSingular}}Type, {{$varNameSingular}}Mapping, wl)
if err != nil {
return err
}
cache.retMapping, err = boil.BindMapping({{$varNameSingular}}Type, {{$varNameSingular}}Mapping, returnColumns)
if err != nil {
return err
}
cache.query = fmt.Sprintf(`INSERT INTO {{.Table.Name}} ("%s") VALUES (%s)`, strings.Join(wl, `","`), strmangle.Placeholders(len(wl), 1, 1))
if len(cache.retMapping) != 0 {
{{if .UseLastInsertID -}}
cache.query += fmt.Sprintf(` RETURNING %s`, strings.Join(returnColumns, ","))
{{else -}}
cache.retQuery = fmt.Sprintf(`SELECT %s FROM {{.Table.Name}} WHERE %s`, strings.Join(returnColumns, `","`), strmangle.WhereClause(1, {{$varNameSingular}}AutoIncPrimaryKeys))
{{else -}}
cache.query += fmt.Sprintf(` RETURNING %s`, strings.Join(returnColumns, ","))
{{end -}}
}
}
value := reflect.Indirect(reflect.ValueOf(o))
{{if .UseLastInsertID}}
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, ins)
@ -99,15 +105,16 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
return errors.Wrap(err, "{{.PkgName}}: unable to populate default values for {{.Table.Name}}")
}
{{else}}
vals := boil.ValuesFromMapping(value, cache.valueMapping)
if len(cache.retMapping) != 0 {
err = exec.QueryRow(cache.query, boil.GetStructValues(o, wl...)...).Scan(boil.GetStructPointers(o, returnColumns...)...)
err = exec.QueryRow(cache.query, vals...).Scan(boil.PtrsFromMapping(value, cache.retMapping)...)
} else {
_, err = exec.Exec(cache.query, boil.GetStructValues(o, wl...)...)
_, err = exec.Exec(cache.query, vals...)
}
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, ins)
fmt.Fprintln(boil.DebugWriter, boil.GetStructValues(o, wl...))
fmt.Fprintln(boil.DebugWriter, cache.query)
fmt.Fprintln(boil.DebugWriter, vals)
}
if err != nil {

View file

@ -40,7 +40,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, updateOnConflict boo
{{$varNameSingular}}Columns,
{{$varNameSingular}}ColumnsWithDefault,
{{$varNameSingular}}ColumnsWithoutDefault,
boil.NonZeroDefaultSet({{$varNameSingular}}ColumnsWithDefault, {{$varNameSingular}}TitleCases, o),
boil.NonZeroDefaultSet({{$varNameSingular}}ColumnsWithDefault, o),
whitelist,
)
update := strmangle.UpdateColumnSet(

View file

@ -17,3 +17,19 @@ type updateCache struct{
query string
valueMapping []uint64
}
func makeCacheKey(wl, nzDefaults []string) string {
buf := strmangle.GetBuffer()
for _, w := range wl {
buf.WriteString(w)
}
for _, nz := range nzDefaults {
buf.WriteString(nz)
}
str := buf.String()
strmangle.PutBuffer(buf)
return str
}