Finish Insert() caching.
This commit is contained in:
parent
793306d749
commit
acad9f7de5
7 changed files with 65 additions and 39 deletions
|
@ -237,12 +237,12 @@ func bind(rows *sql.Rows, obj interface{}, structType, sliceType reflect.Type, b
|
||||||
|
|
||||||
switch bkind {
|
switch bkind {
|
||||||
case kindStruct:
|
case kindStruct:
|
||||||
pointers = ptrsFromMapping(reflect.Indirect(reflect.ValueOf(obj)), mapping)
|
pointers = PtrsFromMapping(reflect.Indirect(reflect.ValueOf(obj)), mapping)
|
||||||
case kindSliceStruct:
|
case kindSliceStruct:
|
||||||
pointers = ptrsFromMapping(oneStruct, mapping)
|
pointers = PtrsFromMapping(oneStruct, mapping)
|
||||||
case kindPtrSliceStruct:
|
case kindPtrSliceStruct:
|
||||||
newStruct = reflect.New(structType)
|
newStruct = reflect.New(structType)
|
||||||
pointers = ptrsFromMapping(reflect.Indirect(newStruct), mapping)
|
pointers = PtrsFromMapping(reflect.Indirect(newStruct), mapping)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -295,19 +295,29 @@ ColLoop:
|
||||||
return ptrs, nil
|
return ptrs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ptrsFromMapping expects to be passed an addressable struct that it's looking
|
// PtrsFromMapping expects to be passed an addressable struct and a mapping
|
||||||
// for things on.
|
// of where to find things. It pulls the pointers out referred to by the mapping.
|
||||||
func ptrsFromMapping(val reflect.Value, mapping []uint64) []interface{} {
|
func PtrsFromMapping(val reflect.Value, mapping []uint64) []interface{} {
|
||||||
ptrs := make([]interface{}, len(mapping))
|
ptrs := make([]interface{}, len(mapping))
|
||||||
for i, m := range 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
|
return ptrs
|
||||||
}
|
}
|
||||||
|
|
||||||
// ptrFromMapping expects to be passed an addressable struct that it's looking
|
// ptrFromMapping expects to be passed an addressable struct that it's looking
|
||||||
// for things on.
|
// 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++ {
|
for i := 0; i < 8; i++ {
|
||||||
v := (mapping >> uint(i*8)) & sentinel
|
v := (mapping >> uint(i*8)) & sentinel
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
if got := *v.Interface().(*int); got != 5 {
|
||||||
t.Error("flat int was wrong:", got)
|
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 {
|
if got := *v.Interface().(*int); got != 0 {
|
||||||
t.Error("flat pointer was wrong:", got)
|
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 {
|
if got := *v.Interface().(*int); got != 6 {
|
||||||
t.Error("nested int was wrong:", got)
|
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 {
|
if got := *v.Interface().(*int); got != 0 {
|
||||||
t.Error("nested pointer was wrong:", got)
|
t.Error("nested pointer was wrong:", got)
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,6 +146,8 @@ var defaultTemplateImports = imports{
|
||||||
`"fmt"`,
|
`"fmt"`,
|
||||||
`"strings"`,
|
`"strings"`,
|
||||||
`"database/sql"`,
|
`"database/sql"`,
|
||||||
|
`"reflect"`,
|
||||||
|
`"sync"`,
|
||||||
`"time"`,
|
`"time"`,
|
||||||
},
|
},
|
||||||
thirdParty: importList{
|
thirdParty: importList{
|
||||||
|
@ -166,6 +168,7 @@ var defaultSingletonTemplateImports = map[string]imports{
|
||||||
"boil_types": {
|
"boil_types": {
|
||||||
thirdParty: importList{
|
thirdParty: importList{
|
||||||
`"github.com/pkg/errors"`,
|
`"github.com/pkg/errors"`,
|
||||||
|
`"github.com/vattle/sqlboiler/strmangle"`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
{{if .Table.IsJoinTable -}}
|
||||||
|
{{else -}}
|
||||||
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
|
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
|
||||||
{{- $tableNameSingular := .Table.Name | singular | titleCase -}}
|
{{- $tableNameSingular := .Table.Name | singular | titleCase -}}
|
||||||
var (
|
var (
|
||||||
|
@ -20,26 +22,14 @@ type (
|
||||||
|
|
||||||
// Cache for insert and update
|
// Cache for insert and update
|
||||||
var (
|
var (
|
||||||
{{$varNameSingular}}Mapping = boil.MakeStructMapping(&{{$tableNameSingular}}{})
|
{{$varNameSingular}}Type = reflect.TypeOf(&{{$tableNameSingular}}{})
|
||||||
{{$varNameSingular}}InsertCacheMut sync.RMutex
|
{{$varNameSingular}}Mapping = boil.MakeStructMapping({{$varNameSingular}}Type)
|
||||||
|
{{$varNameSingular}}InsertCacheMut sync.RWMutex
|
||||||
{{$varNameSingular}}InsertCache = make(map[string]insertCache)
|
{{$varNameSingular}}InsertCache = make(map[string]insertCache)
|
||||||
{{$varNameSingular}}UpdateCacheMut sync.RMutex
|
{{$varNameSingular}}UpdateCacheMut sync.RWMutex
|
||||||
{{$varNameSingular}}UpdateCache = make(map[string]updateCache)
|
{{$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.
|
// Force time package dependency for automated UpdatedAt/CreatedAt.
|
||||||
var _ = time.Second
|
var _ = time.Second
|
||||||
|
{{end -}}
|
||||||
|
|
|
@ -56,20 +56,26 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
|
||||||
whitelist,
|
whitelist,
|
||||||
)
|
)
|
||||||
|
|
||||||
typ := reflect.TypeOf(o)
|
cache.valueMapping, err = boil.BindMapping({{$varNameSingular}}Type, {{$varNameSingular}}Mapping, wl)
|
||||||
cache.valueMapping = boil.BindMapping(typ, {{$varNameSingular}}Mapping, wl)
|
if err != nil {
|
||||||
cache.retMapping = boil.BindMapping(typ, {{$varNameSingular}}Mapping, returnColumns)
|
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))
|
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 len(cache.retMapping) != 0 {
|
||||||
{{if .UseLastInsertID -}}
|
{{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))
|
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 -}}
|
{{end -}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value := reflect.Indirect(reflect.ValueOf(o))
|
||||||
{{if .UseLastInsertID}}
|
{{if .UseLastInsertID}}
|
||||||
if boil.DebugMode {
|
if boil.DebugMode {
|
||||||
fmt.Fprintln(boil.DebugWriter, ins)
|
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}}")
|
return errors.Wrap(err, "{{.PkgName}}: unable to populate default values for {{.Table.Name}}")
|
||||||
}
|
}
|
||||||
{{else}}
|
{{else}}
|
||||||
|
vals := boil.ValuesFromMapping(value, cache.valueMapping)
|
||||||
if len(cache.retMapping) != 0 {
|
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 {
|
} else {
|
||||||
_, err = exec.Exec(cache.query, boil.GetStructValues(o, wl...)...)
|
_, err = exec.Exec(cache.query, vals...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if boil.DebugMode {
|
if boil.DebugMode {
|
||||||
fmt.Fprintln(boil.DebugWriter, ins)
|
fmt.Fprintln(boil.DebugWriter, cache.query)
|
||||||
fmt.Fprintln(boil.DebugWriter, boil.GetStructValues(o, wl...))
|
fmt.Fprintln(boil.DebugWriter, vals)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -40,7 +40,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, updateOnConflict boo
|
||||||
{{$varNameSingular}}Columns,
|
{{$varNameSingular}}Columns,
|
||||||
{{$varNameSingular}}ColumnsWithDefault,
|
{{$varNameSingular}}ColumnsWithDefault,
|
||||||
{{$varNameSingular}}ColumnsWithoutDefault,
|
{{$varNameSingular}}ColumnsWithoutDefault,
|
||||||
boil.NonZeroDefaultSet({{$varNameSingular}}ColumnsWithDefault, {{$varNameSingular}}TitleCases, o),
|
boil.NonZeroDefaultSet({{$varNameSingular}}ColumnsWithDefault, o),
|
||||||
whitelist,
|
whitelist,
|
||||||
)
|
)
|
||||||
update := strmangle.UpdateColumnSet(
|
update := strmangle.UpdateColumnSet(
|
||||||
|
|
|
@ -17,3 +17,19 @@ type updateCache struct{
|
||||||
query string
|
query string
|
||||||
valueMapping []uint64
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue